Overview

Welcome to the hands-on, practical learning portion of Lesson 2 where you will create a single page R Markdown document. I made this page to help guide you in the process. The material below contains a series of assignments and challenges designed to get you comfortable utilizing YAML metadata, Markdown syntax, and R code chunks.

The page itself is written almost entirely in R Markdown, meaning there is no extensive use of anything fancy like complicated CSS or HTML. I will introduce some simple HTML code you can use to jazz up your document a little. You should be able to solve any problem I present by digging around in the raw code on GitHub, consulting the Resources page, using one of the targeted search strategies described in the Problem Solving post, and/or posting a question to the Slack channel.

Some Keys to Success

Knit often. Whenever you make a change to the YAML header, add a new code chunk, etc., re-knit (or render) your document. This is very important. Regular knitting allows you to a) see the effects of a change and b) track down (troubleshoot) issues more easily.

Simply hit the knit button or use the shortcut keys—on MacOS Cmd+Shift+K and Windows Ctrl+Shift+K. Learn to love these shortcut keys. They will save you time.

You can choose how your document is previewed using the drop down menu in the document settings. Preview in Window opens the document in a separate RStudio window and Preview in Viewer Pane lets you see the document in the main RStudio IDE. These are good for quick looks. You should always double-check the actual HTML file because sometimes things look different in RStudio.

Something to consider while you create your page is readability. This not only applies to the final document but also the raw R Markdown code itself. Think about someone digging through your code to figure out how you did something. Or think about yourself coming back to the code after a few years. The better your document is formatted, the easier it will be to understand. In future lessons we will return to some best practices but for now remember, part of what we are doing here is making your science more transparent and reproducible. If your document is confusing to follow then it serves neither of these purposes.

Assignment 1: The Basics

In the first assignment, you will employ some basic techniques to control the look of your document and how R code chunks are rendered. We will cover YAML metadata modifications, setting global chunk options, and writing Markdown content. You will also learn about testing R code first before rendering the final document.

1.1 Make a Document

If you have not already done so, your first task is to create an R Markdown document. Open R Studio and go to File > New File > R Markdown. A window should pop up where you can fill in the details. It is not important what you put here since you can change it at any time. What is important is that Document and HTML are both selected. We will cover other document types in the future. Hit Ok and follow the steps in this graphic. Remember, you do not need to add a file extension when you save the document.


Building your initial R Markdown document.

Building your initial R Markdown document.


Once you have a document built and saved, there should be a .html file in your working directory. Double-click that file—it should open in your default browser. Each time you re-knit the .Rmd file, you can just refresh the browser page or double-click the file again.

1.2 Add Markdown Text

Your first task is to add some content and format the content with Markdown. This doesn’t need to be anything fancy to start. You can either add text as you go or paste a large amount of text in at once. Dealers choice. You can use the Markdown section of Lesson 0 or the Markdown section from the Resources page for reference.

  1. Add headers to give the document structure. Use different header levels.
  2. Add hyperlinks. We will learn about internal links later. For now, just link to outside websites.
  3. Add emphasis formatting like bold, italics, and block text.
  4. Mix and match formatting, like make a hyperlink bold or add italics to block text.
  5. Make a list of items.

1.3 Modify & Test R Code Chunks

Now it is time to get some practice modifying code chunk options so you can gain more control over the behavior of code and result display. If you have your own R code you are more than welcome to use it here. I will use the default code chunks that were added to the .Rmd file. Please see the section on Chunk structure & options from Lesson 2 for more details.

Here are the two default code chunks. As you can see, both have names and the second chunk has a single option.

```{r cars}
summary(cars)
```
```{r pressure, echo=FALSE}
plot(pressure)
```

There are many code chunk options you can control. Which options you use and how you set them will be determined by your needs. Test the behavior of the following options by setting each equal to either TRUE or FALSE. Render the document and see if you can figure out what changed. Each of these has a default value so you may not see a change until you set the alternative value.

  1. echo
  2. collapse
  3. eval
  4. prompt
  5. highlight
  6. include

Next, it is a really good habit to check code chunks as you add them. This will ensure that each chunk works, making it easier to track down problems. If you refer to the first image on this page, you can you have options for Chunk OutputInline and Console. This controls where the output is displayed. Let’s take a quick look at a code chunk in RStudio and see how you test chunks before rendering.

Take a look at the tool bar on the far right. Option 1 is a drop down menu that gives you an alternative way to set code chunk options. Option 2 will Run all Code Chunks Above meaning that RStudio will run all code chunks above the current chunk but not the current chunk itself. And Option 3 will Run the Current Chunk. Incidentally, if you do not see these options it means something is wrong with the chunk.

Go ahead and run the chunk.

1.4 Modify YAML Metadata

You last task is to modify the YAML header to suit your needs and tastes. I would like you to experiment with different options and settings to see what happens in the final document.

  1. Run ?rmarkdown::html_document or ?html_document in the Console to see the header options for an HTML document.
  2. Add a table of contents and include options that modify the behavior of the table of contents.
  3. Add the option to keep the Markdown document. This will save a .md copy of your file.
  4. Open the .md file in a text editor. This is the output from knitr—after all R code has been processed—and what PanDoc uses to generate an HTML file. Keep this file open as you build your document. Pay attention to how your R code is converted to Markdown syntax.
  5. Change the theme. Options are listed on the Convert to an HTML document help page you opened in RStudio. Try a few options and see what happens.
  6. Change the code highlight option. These too are listed on the help page. Try a few options and see what happens.

Assignment 2: Tables

In this assignment, you will explore different methods of incorporating tables in your document. The choice of method depends on a) the type of data, b) the amount of data, and c) the desired output. I will cover a few tools for creating tables but please note there are many options out there, so look around and let us know if you find a tool you like.

For each example, I will use the mtcars data set from the datasets package. The mtcars data set has 32 rows and 11 columns. Feel free to load your own data table or use the mtcars data set.

Tools

You will use four different tools in this assignment for making tables. Here is a summary table of of each tool.

Table types and recommended uses.
Table type Table size Formatting Options Skill Level
markdown small minimal beginner
rmarkdown::paged_table large minimal beginner
knitr::kable + kableExtra small extensive intermediate
DT + DataTables large extensive advanced


2.1 Markdown

The simplest method of building a table is with Markdown syntax. This is a nice option because you can hard code the table right into the document—no need to install and load libraries or write code chunks—and it is easy to implement. The downside is there is minimal functionality available in a Markdown table.

Markdown does not work well for large tables. So I will first grab a subset of mtcars, specifically the first 4 rows and 3 columns. In my code chunk I add the chunk option comment="". This prevents knit from appending a string (default is ##) to the start of each line of results in the final document.

                mpg cyl disp
Mazda RX4      21.0   6  160
Mazda RX4 Wag  21.0   6  160
Datsun 710     22.8   4  108
Hornet 4 Drive 21.4   6  258


Incidentally, the results box above is technically the simplest table you can make, either by calling the data frame mtcars_sub directly or running print.data.frame(mtcars_sub).

Anyway, run this code chunk, copy the results, and make a Markdown table. You can either run the chunk in RStudio without rendering the document (described above) or render the document and copy the results from HTML page. I added a header to the first column. And here is the Markdown table.


Demonstration of the output from pipe_tables Markdown syntax.
model mpg cyl disp
Mazda RX4 21.0 6 160
Mazda RX4 Wag 21.0 6 160
Datsun 710 22.8 4 108
Hornet 4 Drive 21.4 6 258


Since this is a Markdown table, you can add additional Markdown syntax for formatting. See if you can figure out what syntax I added to my table and add some to your table. Also check out the Tables section of PanDoc User’s Guide for other Markdown table options, including how to add a caption. In addition to pipe_tables, you can create multiline_tables grid_tables, and simple_tables.

Something to notice is that the Markdown table spans the entire width of the page—even though it does not need all of that space. As far as I know, there is no way to control this behavior without adding additional HTML formatting.

Recommendation Use Markdown for small, simple tables where styling is not a concern.

2.2 R Markdown Paged Tables

With larger tables, it may not be practical to display the full table inline. So we need a way to shrink a large table so it looks good while still allowing access to the full table.

The next type of table I want you to try are Paged Tables. R Markdown comes with its own built in table function called paged_table. The paged_table function allows pagination of rows and columns making it possible to render a large table in a small space.

It is easy to code paged_table but that ease comes with a small price—limited functionality. Here are the options you do have with paged_table function.

A Markdown table listing the Options for the paged_table function.
Option Description
rows.print Maximum rows to print per page.
max.print Maximum rows in the table (defaults to 1000).
cols.print Maximum columns in the table (defaults to 10).
rownames.print Print row names as part of the table.

A quick side note. You actually need to load the rmarkdown package for paged_table to work. Anyway, this is a good time to return to the first code chunk in your .Rmd file—the chunk called setup that R Markdown added by default.

I like to use this chunk to load all of the packages I need for my document. Using a single chunk for all of my packages helps me keep my document organized. Notice the setup chunk has the option include=FALSE. This prevents the content of the chunk from appearing in the final document, which for me is more stylistically appealing. I can add a sessionInfo() chunk at the end of my document to report all of the packages so this information is available to the reader. We will cover sessionInfo() when we get into more depth on the subject of reproducible. If you do not want to load the library you can run the command like this: rmarkdown::paged_table().

OK, back to the table. Now I can create a table of mtcars with the paged_table function and use an option to limit the number of printed rows to 5 for each page. I used echo=FALSE in my code chunk to hide the code :). By now you should know where to look for a solution.


Notice that for each column, the column class is printed below the name (text enclosed in < >). This is irritating and related to printing a table from a built-in data frame. I have no idea how to fix this (within the confines of R Markdown) but I will work on a solution.

Recommendation Use paged_table for large tables where extensive styling is not a concern.

2.3 Kable Tables

Knitr comes with its own tool for rendering simple tables called kable. The documentation for kable can be found here or by running ?knitr::kable() in the Console. By itself, kable comes with almost no options. We can extend its functionality with the kableExtra package and piping syntax from magrittr. The features of kableExtra are extensive and I will only touch on a few here. The documentation for kableExtra can be found here or by running ?kableExtra in the Console after the package has been installed and loaded.

I highly recommend you learn how to use these packages for making tables.

Again, you will need to load kableExtra and either load the knitr package or run the command like this: knitr::kable().

First, let’s look at the default kable table output. We will use the head of the mtcars data set.


Wow, this table looks terrible.
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1


If we tried to render the entire table by omitting head, we would just get a long, crappy table in our document. Not cool. Lets see if we can jazz this up a bit with kableExtra.

This table looks better
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1

Here I used the pipe operator (%>%) to pass the results of kable to the function kable_styling—a part of the kableExtra package. By running kable_styling as is, I am using defaults for all of the options.

The pipe operator is a powerful tool worth learning.

Back to the table. It certainly looks better than the default kable version but we are missing the ability to page the table. I would like you to run these two commands and look at the output.

This command will include the whole table.

kable(mtcars) %>%
  kable_styling()

And this command will transpose the table (swap rows and columns) using the transpose (t) function. Remember, mtcars has 32 rows and 11 columns but when you transpose the table, it has 11 rows and 32 columns. So it is really wide in the transposed state.

kable(head(t(mtcars))) %>%
  kable_styling()

I hope you agree that neither of these tables are acceptable, especially the second one. Unfortunately, the kableExtra package does not come with an option to add pagination. You can however put the table in a fixed-height, fixed-width (or both) box, and make it scrollable. We can do this by using a pipe operator and the scroll_box function. While we are at it, lets also add tweak some options in kable_styling to make a more handsome table.

Scrollable kable table.
Mazda RX4 Mazda RX4 Wag Datsun 710 Hornet 4 Drive Hornet Sportabout Valiant Duster 360 Merc 240D Merc 230 Merc 280 Merc 280C Merc 450SE Merc 450SL Merc 450SLC Cadillac Fleetwood Lincoln Continental Chrysler Imperial Fiat 128 Honda Civic Toyota Corolla Toyota Corona Dodge Challenger AMC Javelin Camaro Z28 Pontiac Firebird Fiat X1-9 Porsche 914-2 Lotus Europa Ford Pantera L Ferrari Dino Maserati Bora Volvo 142E
mpg 21.00 21.000 22.80 21.400 18.70 18.10 14.30 24.40 22.80 19.20 17.80 16.40 17.30 15.20 10.40 10.400 14.700 32.40 30.400 33.900 21.500 15.50 15.200 13.30 19.200 27.300 26.00 30.400 15.80 19.70 15.00 21.40
cyl 6.00 6.000 4.00 6.000 8.00 6.00 8.00 4.00 4.00 6.00 6.00 8.00 8.00 8.00 8.00 8.000 8.000 4.00 4.000 4.000 4.000 8.00 8.000 8.00 8.000 4.000 4.00 4.000 8.00 6.00 8.00 4.00
disp 160.00 160.000 108.00 258.000 360.00 225.00 360.00 146.70 140.80 167.60 167.60 275.80 275.80 275.80 472.00 460.000 440.000 78.70 75.700 71.100 120.100 318.00 304.000 350.00 400.000 79.000 120.30 95.100 351.00 145.00 301.00 121.00
hp 110.00 110.000 93.00 110.000 175.00 105.00 245.00 62.00 95.00 123.00 123.00 180.00 180.00 180.00 205.00 215.000 230.000 66.00 52.000 65.000 97.000 150.00 150.000 245.00 175.000 66.000 91.00 113.000 264.00 175.00 335.00 109.00
drat 3.90 3.900 3.85 3.080 3.15 2.76 3.21 3.69 3.92 3.92 3.92 3.07 3.07 3.07 2.93 3.000 3.230 4.08 4.930 4.220 3.700 2.76 3.150 3.73 3.080 4.080 4.43 3.770 4.22 3.62 3.54 4.11
wt 2.62 2.875 2.32 3.215 3.44 3.46 3.57 3.19 3.15 3.44 3.44 4.07 3.73 3.78 5.25 5.424 5.345 2.20 1.615 1.835 2.465 3.52 3.435 3.84 3.845 1.935 2.14 1.513 3.17 2.77 3.57 2.78
qsec 16.46 17.020 18.61 19.440 17.02 20.22 15.84 20.00 22.90 18.30 18.90 17.40 17.60 18.00 17.98 17.820 17.420 19.47 18.520 19.900 20.010 16.87 17.300 15.41 17.050 18.900 16.70 16.900 14.50 15.50 14.60 18.60
vs 0.00 0.000 1.00 1.000 0.00 1.00 0.00 1.00 1.00 1.00 1.00 0.00 0.00 0.00 0.00 0.000 0.000 1.00 1.000 1.000 1.000 0.00 0.000 0.00 0.000 1.000 0.00 1.000 0.00 0.00 0.00 1.00
am 1.00 1.000 1.00 0.000 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.000 0.000 1.00 1.000 1.000 0.000 0.00 0.000 0.00 0.000 1.000 1.00 1.000 1.00 1.00 1.00 1.00
gear 4.00 4.000 4.00 3.000 3.00 3.00 3.00 4.00 4.00 4.00 4.00 3.00 3.00 3.00 3.00 3.000 3.000 4.00 4.000 4.000 3.000 3.00 3.000 3.00 3.000 4.000 5.00 5.000 5.00 5.00 5.00 4.00
carb 4.00 4.000 1.00 1.000 2.00 1.00 4.00 2.00 2.00 4.00 4.00 3.00 3.00 3.00 4.00 4.000 4.000 1.00 2.000 1.000 1.000 2.00 2.000 4.00 2.000 1.000 2.00 2.000 4.00 6.00 8.00 2.00


For the scroll_box function I set the width = "100%" rather than specifying a dimension. This ensures the box will always be the width of the page no matter how small the window is.

Even though you cannot make a paged table with kable, there are many styling options available in the kableExtra package that makes this method extremely useful and worth learning. Plus, the code is relatively simple to write.

I want to show you one more feature that is not available the other table methods we cover in this Assignment—floating. Let’s first subset the mtcars data set so we can make a small table. Next we use the full_width and position options to control the size and position of the table.

Here is our code chunk.

mpg cyl disp hp drat wt
Mazda RX4 21.0 6 160 110 3.90 2.620
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875
Datsun 710 22.8 4 108 93 3.85 2.320
Hornet 4 Drive 21.4 6 258 110 3.08 3.215
Hornet Sportabout 18.7 8 360 175 3.15 3.440
Valiant 18.1 6 225 105 2.76 3.460
Duster 360 14.3 8 360 245 3.21 3.570



Let’s say we have a bunch of text that we want to put side-by-side with this small table. Our subsetted mtcars data set now has 7 rows and 6 columns. We can make our table smaller by setting full_width = FALSE in kable_styling and float the table by setting position = "float_right"

Please study the extensive options available in kable and kableExtra and create tables that implement some of the options.



Recommendation Use kable + kableExtra for small tables where extensive styling is desired.

2.4 DT Tables

The last option I want to cover for building tables is implemented using the datatable function from the DT package, an interface to the JavaScript library DataTables. To demonstrate the functionality, I will use a larger data set called USJudgeRatings from the datasets package. USJudgeRatings has 43 rows and 12 columns. This table is too big—horizontally and vertically—to fit on a standard page.

The syntax for the DT::datatable is more complicated than the other methods but that comes with more extensive functionality.

Working with DT::datatable is an advanced level skill. I highly recommend you learn how to use the package, but it will take practice.

Please make sure you are comfortable with the other methods first before trying to use DT::datatable. I promise, if you do not know what you are doing, this package will cause a lot of frustration. That said, I use it all the time because it is awesome.

Moving on. If we run DT on the USJudgeRatings data set without any options the table will spill off the side of the page. Again, not cool. Try to run this command and see what happens.

datatable(USJudgeRatings)

DT::datatable does not page tables horizontally like the paged_table command does (described above). We can set the width of the table and add an option that allows horizontal scrolling. For this we use the options argument. The syntax is to add width = "100%" followed by options = list(), where we put a comma separated list of options. For now, we just include scrollX in our list of options.


Play around with the table a little. As you can see

  • the table now fits in the window,
  • horizontal scrolling in enabled,
  • the page is vertically paged,
  • there is a Show entries drop down, and
  • there is a Search box.

The Show entries and Search box are added by default. We can decide whether to show these options or not. I will save that for later. For now, I want to leave you with a more stylized DT data table to give you a sense of the possibilities. Don’t worry so much about the code—pay attention to the functionality.



I added buttons to download the table to different formats, changed the page length to 5, and changed the values in the Show entries drop down. Play around with the table. There is a lot more to do with this package and we will come back to it often.

Recommendation Use DT::datatable for large tables where extensive styling is desired.

That’s all for this assignment.

Assignment 3: Code

If you are interested in making your science more transparent and reproducible, you need to provide at least two things—the raw data you generated and the code you used to analyze it. Hopefully it is obvious by now that you need to provide access to both components; neither is particularly useful without the other. We will cover data availability in a future lesson. For this assignment, you will practice several different methods for making your code accessible. The method or methods you choose for your own work will depend on the type of analyses and the type of code.

Your assignment is to implement these methods in your document and play around with the different options.

Purl

Knitr comes with a built-in function called purl, which allows you to extract all the R code from an R Markdown document and convert it to an R script. In order to run purl, you must either load the knitr library first (i.e., library(knitr)) and then run purl or call the function directly by running knitr::purl(). We will start by discussing some simple options for running purl and then talk about how you run the command. The basic structure of the command is:

knitr::purl(input="filename.Rmd", documentation = L)

By default, purl uses the base name of the input file as the base name of the output file. If you want to control this behavior, add the option output="filename.R" where filename is whatever you choose.

The option documentation is an integer that specifies the level (L) of documentation to add to the script. You have three choices

  • 0 means output pure code to the script, discard all Markdown text and code chunk details.
  • 1 (the default) means discard all Markdown text but add the chunk headers to the script as commented lines.
  • 2 means to add all Markdown text and code chunks to the script as commented lines.

As far as I know, you cannot run purl from inside an actual code chunk. I have no idea why nor was I able to find an answer. If have an answer or know a solution, please let us know. There easiest way to generate an R script from an R Markdown document with purl to is to run the command in the Console like so:

knitr::purl(input="filename.Rmd", documentation = 1)

Run the purl command using the three options described above for documentation option and look at the output files.

Inline R expressions are ignored by default. For example, if you had an inline R expression like this `r sqrt(2)` the expression would not be included in the R script generated by purl. If you want to include inline expressions in the R script, you need to set the global R option knitr.purl.inline = TRUE before calling knitr::purl().

Remember way back when you generated your initial R Markdown document a default code chunk was added just below the YAML header?

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

If you add knitr.purl.inline = TRUE to that code chunk, all inline expressions will be added to the R script.

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE, knitr.purl.inline = TRUE)
```

The last thing I want to mention is that you can prevent certain code chunks from appearing in the R Script by adding the option purl = FALSE to the chunk. For example, if you add this option to the setup chunk we just discussed that chunk will not appear in the final document.

```{r setup, include=FALSE, purl = FALSE}
knitr::opts_chunk$set(echo = TRUE, knitr.purl.inline = TRUE)
```

Test the behavior of the different options for purl on your document. You can also use this funtion on any R Markdown document to quickly retrieve the code. For example, if you download the Rmd file for this page from GitHub you can run purl to quickly extract the R code.

Recommendation Use purl to generate a simple R script version of your R Markdown document after the document is finished and saved. You can then link to the file somewhere in your document.

Download Rmd

I hope by now you have seen that any document I present in this course has a link to a GitHub repo where you can download or copy the .Rmd file. That’s great and all, but wouldn’t it be nice if you could do it right from the HTML page? Well, you can by adding one simple line of code as a property of html_document in your YAML header —code_download: true.

output:
  html_document:
    theme: journal
    toc: true
    toc_float: true
    toc_depth: 3
    highlight: tango
    code_download: true

You could of course set the property to false except this is the default value and nothing will change. Look back at the top of this page and you should now see a Code button in the upper right corner. Click on the drop down and select Download Rmd and this entire page should be saved to your Downloads directory.

Go ahead and add this option to your YAML header.

Code Folding

I have mentioned a time or two that the benefits of using R Markdown is the ability to execute and display code in your final document. If you go back to the default setup chunk at the top of your .Rmd you should see this:

knitr::opts_chunk$set(echo = TRUE)

I discussed this chunk previously in #5 of the Chunk structure & options section in Lesson 2. Briefly, this is a global command that ensures all R code chunks are visible in the final document, unless you escape this behavior by using echo = FALSE in a particular chunk. Of course, you could also set the global option to FALSE as is knitr::opts_chunk$set(echo = FALSE) and then none of the R code would be visible at all. This is a perfectly fine option in some situations but not in others.

Let’s face it—code takes up a lot of space in a document and large code chunks are not particularly pleasing to look at. You may encounter situations where you both want the code available on a page but you also want to hide the code. For this we use a technique called code folding. Near the bottom of Lesson 0, I used some simple HTML to make a section that folds the R code for the Clifford Attractor. There is a little Show/hide button that allows you to look at the code if you want to; otherwise it is hidden by default. But this approach is a little clunky because you must a) know some HTML and b) include this for every chunk.

R Markdown has a similar functionality for showing and hiding code but it only takes a single line of code added to the YAML header. Again, return to your YAML header and add the argument code_folding: as a nested property of html_document:. Your two options for code_folding: are show and hide.

output:
  html_document:
    theme: journal
    toc: true
    toc_float: true
    toc_depth: 3
    highlight: tango
    code_download: true
    code_folding: hide

Once you add this to the YAML header, the drop down Code button in the upper right corner of the page should now include Show All Code and Hide All Code. This allows the user to specify how they want to view the code in the document. Either property you set for code_folding will be the default state for the entire document.

You should also notice that a new Code button appears next to every code chunk in your document. Again, if you want to exclude the code from individual chunks, just set echo = FALSE for that chunk and the code will not be included at all.

Add code_folding: argument to your YAML header and set a property value.


As far as I know there is no way of folding the results of a code chunk or folding indivudual chunks unless you use HTML.

That’s all for this assignment.

Session Info

## R version 3.6.1 (2019-07-05)
## Platform: x86_64-apple-darwin15.6.0 (64-bit)
## Running under: macOS Catalina 10.15.3
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRblas.0.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] DT_0.12          rmarkdown_2.1    kableExtra_1.1.0 epuRate_0.1     
## [5] knitr_1.28      
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.4        later_1.0.0       highr_0.8         compiler_3.6.1   
##  [5] pillar_1.4.3      base64enc_0.1-3   tools_3.6.1       digest_0.6.25    
##  [9] jsonlite_1.6.1    evaluate_0.14     lifecycle_0.2.0   tibble_3.0.0     
## [13] viridisLite_0.3.0 pkgconfig_2.0.3   rlang_0.4.5       shiny_1.4.0      
## [17] cli_2.0.2         rstudioapi_0.11   crosstalk_1.0.0   yaml_2.2.1       
## [21] xfun_0.13         fastmap_1.0.1     stringr_1.4.0     httr_1.4.1       
## [25] xml2_1.2.2        htmlwidgets_1.5.1 vctrs_0.2.4       hms_0.5.3        
## [29] webshot_0.5.2     glue_1.4.0        R6_2.4.1          fansi_0.4.1      
## [33] readr_1.3.1       magrittr_1.5      promises_1.1.0    scales_1.1.0     
## [37] ellipsis_0.3.0    htmltools_0.4.0   assertthat_0.2.1  rvest_0.3.5      
## [41] xtable_1.8-4      mime_0.9          colorspace_1.4-1  httpuv_1.5.2     
## [45] stringi_1.4.6     munsell_0.5.0     crayon_1.3.4
LS0tCnRpdGxlOiAiW0xlc3NvbiAyOiBZb3VyIFByYWN0aWNhbCBQYWdlXShodHRwczovL2dpdGh1Yi5jb20vc3RyaS1jb24vZGMtc2luZ2xlL2Jsb2IvbWFzdGVyL2luZGV4LlJtZCkiCmF1dGhvcjogImJ5IEphcnJvZCIKZGF0ZTogImByIGZvcm1hdChTeXMudGltZSgpLCAnJWQgJUIsICVZJylgIgpzbWFydDogdHJ1ZQpvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBqb3VybmFsCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBrZWVwX21kOiB0cnVlCiAgICBzZWxmX2NvbnRhaW5lZDogdHJ1ZQogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgY29kZV9mb2xkaW5nOiBoaWRlCiNvdXRwdXQ6CiMgIGVwdVJhdGU6OmVwdXJhdGU6CiMgICAgdG9jOiBUUlVFCiMgICAgbnVtYmVyX3NlY3Rpb25zOiBGQUxTRQojICAgIGNvZGVfZm9sZGluZzogInNob3ciCmVkaXRvcl9vcHRpb25zOgogIGNodW5rX291dHB1dF90eXBlOiBpbmxpbmUKLS0tCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBrbml0ci5wdXJsLmlubGluZSA9IFRSVUUpCnNldC5zZWVkKDkxMSkKYGBgCgpgYGB7ciBsb2FkX2xpYnMsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoa25pdHIpCmxpYnJhcnkoZXB1UmF0ZSkKbGlicmFyeShrYWJsZUV4dHJhKQpsaWJyYXJ5KHJtYXJrZG93bikKbGlicmFyeShEVCkKYGBgCgojIyBPdmVydmlldwoKV2VsY29tZSB0byB0aGUgaGFuZHMtb24sIHByYWN0aWNhbCBsZWFybmluZyBwb3J0aW9uIG9mIFtMZXNzb24gMl0oaHR0cHM6Ly9zdHJpLWNvbi5naXRodWIuaW8vZGF0YS1jdXJhdGlvbi8yMDIwLzA0LzA5L2xlc3Nvbi0yLykgd2hlcmUgeW91IHdpbGwgY3JlYXRlIGEgc2luZ2xlIHBhZ2UgUiBNYXJrZG93biBkb2N1bWVudC4gSSBtYWRlIHRoaXMgcGFnZSB0byBoZWxwIGd1aWRlIHlvdSBpbiB0aGUgcHJvY2Vzcy4gVGhlIG1hdGVyaWFsIGJlbG93IGNvbnRhaW5zIGEgc2VyaWVzIG9mIGFzc2lnbm1lbnRzIGFuZCBjaGFsbGVuZ2VzIGRlc2lnbmVkIHRvIGdldCB5b3UgY29tZm9ydGFibGUgdXRpbGl6aW5nIFtZQU1MIG1ldGFkYXRhXShodHRwczovL3N0cmktY29uLmdpdGh1Yi5pby9kYXRhLWN1cmF0aW9uLzIwMjAvMDQvMDkvbGVzc29uLTIvI3RoZS15YW1sLWhlYWRlci0xKSwgW01hcmtkb3duIHN5bnRheF0oaHR0cHM6Ly9zdHJpLWNvbi5naXRodWIuaW8vZGF0YS1jdXJhdGlvbi8yMDIwLzA0LzA5L2xlc3Nvbi0yLyNtYXJrZG93bi1mb3JtYXR0ZWQtdGV4dC0xKSwgYW5kIFtSIGNvZGUgY2h1bmtzXShodHRwczovL3N0cmktY29uLmdpdGh1Yi5pby9kYXRhLWN1cmF0aW9uLzIwMjAvMDQvMDkvbGVzc29uLTIvI3ItY29kZS1jaHVua3MtMSkuCgpUaGUgcGFnZSBpdHNlbGYgaXMgd3JpdHRlbiBhbG1vc3QgZW50aXJlbHkgaW4gUiBNYXJrZG93biwgbWVhbmluZyB0aGVyZSBpcyBubyBleHRlbnNpdmUgdXNlIG9mIGFueXRoaW5nIGZhbmN5IGxpa2UgY29tcGxpY2F0ZWQgIENTUyBvciBIVE1MLiBJIHdpbGwgaW50cm9kdWNlIHNvbWUgc2ltcGxlIEhUTUwgY29kZSB5b3UgY2FuIHVzZSB0byBqYXp6IHVwIHlvdXIgZG9jdW1lbnQgYSBsaXR0bGUuIFlvdSBzaG91bGQgYmUgYWJsZSB0byBzb2x2ZSBhbnkgcHJvYmxlbSBJIHByZXNlbnQgYnkgZGlnZ2luZyBhcm91bmQgaW4gdGhlIHJhdyBjb2RlIG9uIEdpdEh1YiwgY29uc3VsdGluZyB0aGUgW1Jlc291cmNlcyBwYWdlXShodHRwczovL3N0cmktY29uLmdpdGh1Yi5pby9kYXRhLWN1cmF0aW9uL3BhZ2UvcmVzb3VyY2VzLyksIHVzaW5nIG9uZSBvZiB0aGUgdGFyZ2V0ZWQgc2VhcmNoIHN0cmF0ZWdpZXMgZGVzY3JpYmVkIGluIHRoZSBbUHJvYmxlbSBTb2x2aW5nIHBvc3RdKGh0dHBzOi8vc3RyaS1jb24uZ2l0aHViLmlvL2RhdGEtY3VyYXRpb24vMjAyMC8wNC8wMy9oZWxwLyksIGFuZC9vciBwb3N0aW5nIGEgcXVlc3Rpb24gdG8gdGhlIFNsYWNrIGNoYW5uZWwuCgojIyBTb21lIEtleXMgdG8gU3VjY2VzcwoKPiAqKktuaXQgb2Z0ZW4qKi4gV2hlbmV2ZXIgeW91IG1ha2UgYSBjaGFuZ2UgdG8gdGhlIFlBTUwgaGVhZGVyLCBhZGQgYSBuZXcgY29kZSBjaHVuaywgZXRjLiwgcmUta25pdCAob3IgcmVuZGVyKSB5b3VyIGRvY3VtZW50LiBUaGlzIGlzIHZlcnkgaW1wb3J0YW50LiBSZWd1bGFyIGtuaXR0aW5nIGFsbG93cyB5b3UgdG8gKiphKiopIHNlZSB0aGUgZWZmZWN0cyBvZiBhIGNoYW5nZSBhbmQgKipiKiopIHRyYWNrIGRvd24gKHRyb3VibGVzaG9vdCkgaXNzdWVzIG1vcmUgZWFzaWx5Lgo+Cj4gU2ltcGx5IGhpdCB0aGUga25pdCBidXR0b24gb3IgdXNlIHRoZSBzaG9ydGN1dCBrZXlzLS0tb24gTWFjT1MgYENtZGArYFNoaWZ0YCtgS2AgYW5kIFdpbmRvd3MgYEN0cmxgK2BTaGlmdGArYEtgLiBMZWFybiB0byBsb3ZlIHRoZXNlIHNob3J0Y3V0IGtleXMuIFRoZXkgd2lsbCBzYXZlIHlvdSB0aW1lLgoKWW91IGNhbiBjaG9vc2UgaG93IHlvdXIgZG9jdW1lbnQgaXMgcHJldmlld2VkIHVzaW5nIHRoZSBkcm9wIGRvd24gbWVudSBpbiB0aGUgZG9jdW1lbnQgc2V0dGluZ3MuIGBQcmV2aWV3IGluIFdpbmRvd2Agb3BlbnMgdGhlIGRvY3VtZW50IGluIGEgc2VwYXJhdGUgUlN0dWRpbyB3aW5kb3cgYW5kIGBQcmV2aWV3IGluIFZpZXdlciBQYW5lYCBsZXRzIHlvdSBzZWUgdGhlIGRvY3VtZW50IGluIHRoZSBtYWluIFJTdHVkaW8gSURFLiBUaGVzZSBhcmUgZ29vZCBmb3IgKnF1aWNrKiBsb29rcy4gWW91IHNob3VsZCAqKmFsd2F5cyoqIGRvdWJsZS1jaGVjayB0aGUgYWN0dWFsIEhUTUwgZmlsZSBiZWNhdXNlIHNvbWV0aW1lcyB0aGluZ3MgbG9vayBkaWZmZXJlbnQgaW4gUlN0dWRpby4KPGJyLz4KCiFbXShmaWxlcy9wcmV2aWV3LnBuZykKClNvbWV0aGluZyB0byBjb25zaWRlciB3aGlsZSB5b3UgY3JlYXRlIHlvdXIgcGFnZSBpcyAqcmVhZGFiaWxpdHkqLiBUaGlzIG5vdCBvbmx5IGFwcGxpZXMgdG8gdGhlIGZpbmFsIGRvY3VtZW50IGJ1dCBhbHNvIHRoZSByYXcgUiBNYXJrZG93biBjb2RlIGl0c2VsZi4gVGhpbmsgYWJvdXQgc29tZW9uZSBkaWdnaW5nIHRocm91Z2ggeW91ciBjb2RlIHRvIGZpZ3VyZSBvdXQgaG93IHlvdSBkaWQgc29tZXRoaW5nLiBPciB0aGluayBhYm91dCB5b3Vyc2VsZiBjb21pbmcgYmFjayB0byB0aGUgY29kZSBhZnRlciBhIGZldyB5ZWFycy4gVGhlIGJldHRlciB5b3VyIGRvY3VtZW50IGlzIGZvcm1hdHRlZCwgdGhlIGVhc2llciBpdCB3aWxsIGJlIHRvIHVuZGVyc3RhbmQuIEluIGZ1dHVyZSBsZXNzb25zIHdlIHdpbGwgcmV0dXJuIHRvIHNvbWUgYmVzdCBwcmFjdGljZXMgYnV0IGZvciBub3cgcmVtZW1iZXIsIHBhcnQgb2Ygd2hhdCB3ZSBhcmUgZG9pbmcgaGVyZSBpcyBtYWtpbmcgeW91ciBzY2llbmNlIG1vcmUgKnRyYW5zcGFyZW50KiBhbmQgKnJlcHJvZHVjaWJsZSouIElmIHlvdXIgZG9jdW1lbnQgaXMgY29uZnVzaW5nIHRvIGZvbGxvdyB0aGVuIGl0IHNlcnZlcyBuZWl0aGVyIG9mIHRoZXNlIHB1cnBvc2VzLgoKIyMgQXNzaWdubWVudCAxOiBUaGUgQmFzaWNzCgpJbiB0aGUgZmlyc3QgYXNzaWdubWVudCwgeW91IHdpbGwgZW1wbG95IHNvbWUgYmFzaWMgdGVjaG5pcXVlcyB0byBjb250cm9sIHRoZSBsb29rIG9mIHlvdXIgZG9jdW1lbnQgYW5kIGhvdyBSIGNvZGUgY2h1bmtzIGFyZSByZW5kZXJlZC4gV2Ugd2lsbCBjb3ZlciBZQU1MIG1ldGFkYXRhIG1vZGlmaWNhdGlvbnMsIHNldHRpbmcgZ2xvYmFsIGNodW5rIG9wdGlvbnMsIGFuZCB3cml0aW5nIE1hcmtkb3duIGNvbnRlbnQuIFlvdSB3aWxsIGFsc28gbGVhcm4gYWJvdXQgdGVzdGluZyBSIGNvZGUgZmlyc3QgYmVmb3JlIHJlbmRlcmluZyB0aGUgZmluYWwgZG9jdW1lbnQuCgojIyMgMS4xIE1ha2UgYSBEb2N1bWVudAoKSWYgeW91IGhhdmUgbm90IGFscmVhZHkgZG9uZSBzbywgeW91ciBmaXJzdCB0YXNrIGlzIHRvIGNyZWF0ZSBhbiBSIE1hcmtkb3duIGRvY3VtZW50LiBPcGVuIFIgU3R1ZGlvIGFuZCBnbyB0byBgRmlsZSA+IE5ldyBGaWxlID4gUiBNYXJrZG93bmAuIEEgd2luZG93IHNob3VsZCBwb3AgdXAgd2hlcmUgeW91IGNhbiBmaWxsIGluIHRoZSBkZXRhaWxzLiBJdCBpcyBub3QgaW1wb3J0YW50IHdoYXQgeW91IHB1dCBoZXJlIHNpbmNlIHlvdSBjYW4gY2hhbmdlIGl0IGF0IGFueSB0aW1lLiBXaGF0IGlzIGltcG9ydGFudCBpcyB0aGF0ICoqRG9jdW1lbnQqKiBhbmQgKipIVE1MKiogYXJlIGJvdGggc2VsZWN0ZWQuIFdlIHdpbGwgY292ZXIgb3RoZXIgZG9jdW1lbnQgdHlwZXMgaW4gdGhlIGZ1dHVyZS4gSGl0IGBPa2AgYW5kIGZvbGxvdyB0aGUgc3RlcHMgaW4gdGhpcyBncmFwaGljLiBSZW1lbWJlciwgeW91IGRvIG5vdCBuZWVkIHRvIGFkZCBhIGZpbGUgZXh0ZW5zaW9uIHdoZW4geW91IHNhdmUgdGhlIGRvY3VtZW50LgoKPGJyLz4KCmBgYHtyIG1ha2Vfcm1kLCBlY2hvPUZBTFNFLCBjYWNoZT1UUlVFLCBmaWcuY2FwPSJCdWlsZGluZyB5b3VyIGluaXRpYWwgUiBNYXJrZG93biBkb2N1bWVudC4iIH0KaW5jbHVkZV9ncmFwaGljcygiZmlsZXMvbWFrZS1ybWQuZ2lmIikKYGBgCgo8YnIvPgoKT25jZSB5b3UgaGF2ZSBhIGRvY3VtZW50IGJ1aWx0IGFuZCBzYXZlZCwgdGhlcmUgc2hvdWxkIGJlIGEgYC5odG1sYCBmaWxlIGluIHlvdXIgd29ya2luZyBkaXJlY3RvcnkuIERvdWJsZS1jbGljayB0aGF0IGZpbGUtLS1pdCBzaG91bGQgb3BlbiBpbiB5b3VyIGRlZmF1bHQgYnJvd3Nlci4gRWFjaCB0aW1lIHlvdSByZS1rbml0IHRoZSBgLlJtZGAgZmlsZSwgeW91IGNhbiBqdXN0IHJlZnJlc2ggdGhlIGJyb3dzZXIgcGFnZSBvciBkb3VibGUtY2xpY2sgdGhlIGZpbGUgYWdhaW4uCgojIyMgMS4yIEFkZCBNYXJrZG93biBUZXh0CgpZb3VyIGZpcnN0IHRhc2sgaXMgdG8gYWRkIHNvbWUgY29udGVudCBhbmQgZm9ybWF0IHRoZSBjb250ZW50IHdpdGggTWFya2Rvd24uIFRoaXMgZG9lc24ndCBuZWVkIHRvIGJlIGFueXRoaW5nIGZhbmN5IHRvIHN0YXJ0LiBZb3UgY2FuIGVpdGhlciBhZGQgdGV4dCBhcyB5b3UgZ28gb3IgcGFzdGUgYSBsYXJnZSBhbW91bnQgb2YgdGV4dCBpbiBhdCBvbmNlLiBEZWFsZXJzIGNob2ljZS4gWW91IGNhbiB1c2UgdGhlIFtNYXJrZG93bl0oaHR0cHM6Ly9zdHJpLWNvbi5naXRodWIuaW8vZGF0YS1jdXJhdGlvbi8yMDIwLzAzLzI4L2xlc3Nvbi0wLyNtYXJrZG93bi0zKSBzZWN0aW9uIG9mIExlc3NvbiAwIG9yIHRoZSBbTWFya2Rvd25dKGh0dHBzOi8vc3RyaS1jb24uZ2l0aHViLmlvL2RhdGEtY3VyYXRpb24vcGFnZS9yZXNvdXJjZXMvI21hcmtkb3duKSBzZWN0aW9uIGZyb20gdGhlIFJlc291cmNlcyBwYWdlIGZvciByZWZlcmVuY2UuCgoxKSBBZGQgaGVhZGVycyB0byBnaXZlIHRoZSBkb2N1bWVudCBzdHJ1Y3R1cmUuIFVzZSBkaWZmZXJlbnQgaGVhZGVyIGxldmVscy4KMikgQWRkIGh5cGVybGlua3MuIFdlIHdpbGwgbGVhcm4gYWJvdXQgKmludGVybmFsKiBsaW5rcyBsYXRlci4gRm9yIG5vdywganVzdCBsaW5rIHRvIG91dHNpZGUgd2Vic2l0ZXMuCjMpIEFkZCBlbXBoYXNpcyBmb3JtYXR0aW5nIGxpa2UgYm9sZCwgaXRhbGljcywgYW5kIGJsb2NrIHRleHQuCjQpIE1peCBhbmQgbWF0Y2ggZm9ybWF0dGluZywgbGlrZSBtYWtlIGEgaHlwZXJsaW5rIGJvbGQgb3IgYWRkIGl0YWxpY3MgdG8gYmxvY2sgdGV4dC4KNSkgTWFrZSBhIGxpc3Qgb2YgaXRlbXMuCgojIyMgMS4zIE1vZGlmeSAmIFRlc3QgUiBDb2RlIENodW5rcwoKTm93IGl0IGlzIHRpbWUgdG8gZ2V0IHNvbWUgcHJhY3RpY2UgbW9kaWZ5aW5nIGNvZGUgY2h1bmsgb3B0aW9ucyBzbyB5b3UgY2FuIGdhaW4gbW9yZSBjb250cm9sIG92ZXIgdGhlIGJlaGF2aW9yIG9mIGNvZGUgYW5kIHJlc3VsdCBkaXNwbGF5LiBJZiB5b3UgaGF2ZSB5b3VyIG93biBSIGNvZGUgeW91IGFyZSBtb3JlIHRoYW4gd2VsY29tZSB0byB1c2UgaXQgaGVyZS4gSSB3aWxsIHVzZSB0aGUgZGVmYXVsdCBjb2RlIGNodW5rcyB0aGF0IHdlcmUgYWRkZWQgdG8gdGhlIGAuUm1kYCBmaWxlLiBQbGVhc2Ugc2VlIHRoZSBzZWN0aW9uIG9uIFtDaHVuayBzdHJ1Y3R1cmUgJiBvcHRpb25zXShodHRwczovL3N0cmktY29uLmdpdGh1Yi5pby9kYXRhLWN1cmF0aW9uLzIwMjAvMDQvMDkvbGVzc29uLTIvI2NodW5rLXN0cnVjdHVyZS1vcHRpb25zLTEpIGZyb20gTGVzc29uIDIgZm9yIG1vcmUgZGV0YWlscy4KCkhlcmUgYXJlIHRoZSB0d28gZGVmYXVsdCBjb2RlIGNodW5rcy4gQXMgeW91IGNhbiBzZWUsIGJvdGggaGF2ZSBuYW1lcyBhbmQgdGhlIHNlY29uZCBjaHVuayBoYXMgYSBzaW5nbGUgb3B0aW9uLgoKYGBgYApgYGB7ciBjYXJzfWByICcnYApzdW1tYXJ5KGNhcnMpCmBgYApgYGBgCgpgYGBgCmBgYHtyIHByZXNzdXJlLCBlY2hvPUZBTFNFfWByICcnYApwbG90KHByZXNzdXJlKQpgYGAKYGBgYAoKVGhlcmUgYXJlIG1hbnkgY29kZSBjaHVuayBvcHRpb25zIHlvdSBjYW4gY29udHJvbC4gV2hpY2ggb3B0aW9ucyB5b3UgdXNlIGFuZCBob3cgeW91IHNldCB0aGVtIHdpbGwgYmUgZGV0ZXJtaW5lZCBieSB5b3VyIG5lZWRzLiBUZXN0IHRoZSBiZWhhdmlvciBvZiB0aGUgZm9sbG93aW5nIG9wdGlvbnMgYnkgc2V0dGluZyBlYWNoIGVxdWFsIHRvIGVpdGhlciBgVFJVRWAgb3IgYEZBTFNFYC4gUmVuZGVyIHRoZSBkb2N1bWVudCBhbmQgc2VlIGlmIHlvdSBjYW4gZmlndXJlIG91dCB3aGF0IGNoYW5nZWQuIEVhY2ggb2YgdGhlc2UgaGFzIGEgZGVmYXVsdCB2YWx1ZSBzbyB5b3UgbWF5IG5vdCBzZWUgYSBjaGFuZ2UgdW50aWwgeW91IHNldCB0aGUgYWx0ZXJuYXRpdmUgdmFsdWUuCgoxKSBgZWNob2AKMikgYGNvbGxhcHNlYAozKSBgZXZhbGAKNCkgYHByb21wdGAKNSkgYGhpZ2hsaWdodGAKNikgYGluY2x1ZGVgCgpOZXh0LCBpdCBpcyBhIHJlYWxseSBnb29kIGhhYml0IHRvIGNoZWNrIGNvZGUgY2h1bmtzIGFzIHlvdSBhZGQgdGhlbS4gVGhpcyB3aWxsIGVuc3VyZSB0aGF0IGVhY2ggY2h1bmsgd29ya3MsIG1ha2luZyBpdCBlYXNpZXIgdG8gdHJhY2sgZG93biBwcm9ibGVtcy4gSWYgeW91IHJlZmVyIHRvIHRoZSBmaXJzdCBpbWFnZSBvbiB0aGlzIHBhZ2UsIHlvdSBjYW4geW91IGhhdmUgb3B0aW9ucyBmb3IgKipDaHVuayBPdXRwdXQqKi0tLSpJbmxpbmUqIGFuZCAqQ29uc29sZSouIFRoaXMgY29udHJvbHMgd2hlcmUgdGhlIG91dHB1dCBpcyBkaXNwbGF5ZWQuIExldCdzIHRha2UgYSBxdWljayBsb29rIGF0IGEgY29kZSBjaHVuayBpbiBSU3R1ZGlvIGFuZCBzZWUgaG93IHlvdSB0ZXN0IGNodW5rcyBiZWZvcmUgcmVuZGVyaW5nLgoKIVtdKGZpbGVzL3J1bi1jaHVuay5wbmcpCgpUYWtlIGEgbG9vayBhdCB0aGUgdG9vbCBiYXIgb24gdGhlIGZhciByaWdodC4gKipPcHRpb24gMSoqIGlzIGEgZHJvcCBkb3duIG1lbnUgdGhhdCBnaXZlcyB5b3UgYW4gYWx0ZXJuYXRpdmUgd2F5IHRvIHNldCBjb2RlIGNodW5rIG9wdGlvbnMuICoqT3B0aW9uIDIqKiB3aWxsICpSdW4gYWxsIENvZGUgQ2h1bmtzIEFib3ZlKiBtZWFuaW5nIHRoYXQgUlN0dWRpbyB3aWxsIHJ1biBhbGwgY29kZSBjaHVua3MgYWJvdmUgdGhlIGN1cnJlbnQgY2h1bmsgYnV0IG5vdCB0aGUgY3VycmVudCBjaHVuayBpdHNlbGYuIEFuZCAqKk9wdGlvbiAzKiogd2lsbCAqUnVuIHRoZSBDdXJyZW50IENodW5rKi4gSW5jaWRlbnRhbGx5LCBpZiB5b3UgZG8gbm90IHNlZSB0aGVzZSBvcHRpb25zIGl0IG1lYW5zIHNvbWV0aGluZyBpcyB3cm9uZyB3aXRoIHRoZSBjaHVuay4KCkdvIGFoZWFkIGFuZCBydW4gdGhlIGNodW5rLgoKIyMjIDEuNCBNb2RpZnkgWUFNTCBNZXRhZGF0YQoKWW91IGxhc3QgdGFzayBpcyB0byBtb2RpZnkgdGhlIFlBTUwgaGVhZGVyIHRvIHN1aXQgeW91ciBuZWVkcyBhbmQgdGFzdGVzLiBJIHdvdWxkIGxpa2UgeW91IHRvIGV4cGVyaW1lbnQgd2l0aCBkaWZmZXJlbnQgb3B0aW9ucyBhbmQgc2V0dGluZ3MgdG8gc2VlIHdoYXQgaGFwcGVucyBpbiB0aGUgZmluYWwgZG9jdW1lbnQuCgoxKSBSdW4gYD9ybWFya2Rvd246Omh0bWxfZG9jdW1lbnRgIG9yIGA/aHRtbF9kb2N1bWVudGAgaW4gdGhlIENvbnNvbGUgdG8gc2VlIHRoZSBoZWFkZXIgb3B0aW9ucyBmb3IgYW4gSFRNTCBkb2N1bWVudC4KMikgQWRkIGEgdGFibGUgb2YgY29udGVudHMgYW5kIGluY2x1ZGUgb3B0aW9ucyB0aGF0IG1vZGlmeSB0aGUgYmVoYXZpb3Igb2YgdGhlIHRhYmxlIG9mIGNvbnRlbnRzLgozKSBBZGQgdGhlIG9wdGlvbiB0byBrZWVwIHRoZSBNYXJrZG93biBkb2N1bWVudC4gVGhpcyB3aWxsIHNhdmUgYSBgLm1kYCBjb3B5IG9mIHlvdXIgZmlsZS4KNCkgT3BlbiB0aGUgYC5tZGAgZmlsZSBpbiBhIHRleHQgZWRpdG9yLiBUaGlzIGlzIHRoZSBvdXRwdXQgZnJvbSBga25pdHJgLS0tYWZ0ZXIgYWxsIFIgY29kZSBoYXMgYmVlbiBwcm9jZXNzZWQtLS1hbmQgd2hhdCBQYW5Eb2MgdXNlcyB0byBnZW5lcmF0ZSBhbiBIVE1MIGZpbGUuIEtlZXAgdGhpcyBmaWxlIG9wZW4gYXMgeW91IGJ1aWxkIHlvdXIgZG9jdW1lbnQuIFBheSBhdHRlbnRpb24gdG8gaG93IHlvdXIgUiBjb2RlIGlzIGNvbnZlcnRlZCB0byBNYXJrZG93biBzeW50YXguCjUpIENoYW5nZSB0aGUgdGhlbWUuIE9wdGlvbnMgYXJlIGxpc3RlZCBvbiB0aGUgKkNvbnZlcnQgdG8gYW4gSFRNTCBkb2N1bWVudCogaGVscCBwYWdlIHlvdSBvcGVuZWQgaW4gUlN0dWRpby4gVHJ5IGEgZmV3IG9wdGlvbnMgYW5kIHNlZSB3aGF0IGhhcHBlbnMuCjYpIENoYW5nZSB0aGUgY29kZSBoaWdobGlnaHQgb3B0aW9uLiBUaGVzZSB0b28gYXJlIGxpc3RlZCBvbiB0aGUgaGVscCBwYWdlLiBUcnkgYSBmZXcgb3B0aW9ucyBhbmQgc2VlIHdoYXQgaGFwcGVucy4KCiMjIEFzc2lnbm1lbnQgMjogVGFibGVzCgpJbiB0aGlzIGFzc2lnbm1lbnQsIHlvdSB3aWxsIGV4cGxvcmUgZGlmZmVyZW50IG1ldGhvZHMgb2YgaW5jb3Jwb3JhdGluZyB0YWJsZXMgaW4geW91ciBkb2N1bWVudC4gVGhlIGNob2ljZSBvZiBtZXRob2QgZGVwZW5kcyBvbiAqKmEqKikgdGhlIHR5cGUgb2YgZGF0YSwgKipiKiopIHRoZSBhbW91bnQgb2YgZGF0YSwgYW5kICoqYyoqKSB0aGUgZGVzaXJlZCBvdXRwdXQuIEkgd2lsbCBjb3ZlciBhIGZldyB0b29scyBmb3IgY3JlYXRpbmcgdGFibGVzIGJ1dCBwbGVhc2Ugbm90ZSB0aGVyZSBhcmUgW21hbnkgb3B0aW9uc10oaHR0cHM6Ly9yZm9ydGhlcmVzdG9mdXMuY29tLzIwMTkvMTEvaG93LXRvLW1ha2UtYmVhdXRpZnVsLXRhYmxlcy1pbi1yLykgb3V0IHRoZXJlLCBzbyBsb29rIGFyb3VuZCBhbmQgbGV0IHVzIGtub3cgaWYgeW91IGZpbmQgYSB0b29sIHlvdSBsaWtlLgoKRm9yIGVhY2ggZXhhbXBsZSwgSSB3aWxsIHVzZSB0aGUgYG10Y2Fyc2AgZGF0YSBzZXQgZnJvbSB0aGUgYGRhdGFzZXRzYCBwYWNrYWdlLiBUaGUgYG10Y2Fyc2AgZGF0YSBzZXQgaGFzIGByIG5yb3cobXRjYXJzKWAgcm93cyBhbmQgYHIgbmNvbChtdGNhcnMpYCBjb2x1bW5zLiBGZWVsIGZyZWUgdG8gbG9hZCB5b3VyIG93biBkYXRhIHRhYmxlIG9yIHVzZSB0aGUgYG10Y2Fyc2AgZGF0YSBzZXQuCgojIyMgVG9vbHMKCllvdSB3aWxsIHVzZSBmb3VyIGRpZmZlcmVudCB0b29scyBpbiB0aGlzIGFzc2lnbm1lbnQgZm9yIG1ha2luZyB0YWJsZXMuIEhlcmUgaXMgYSBzdW1tYXJ5IHRhYmxlIG9mIG9mIGVhY2ggdG9vbC4gCgp8IFRhYmxlIHR5cGUgICAgICAgICAgICAgICAgICAgIHwgVGFibGUgc2l6ZSAgICAgICB8ICBGb3JtYXR0aW5nIE9wdGlvbnMgIHwgU2tpbGwgTGV2ZWwgICAgICB8CnwtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS0tLS0tLS0tLS0tOnw6LS0tLS0tLS0tLS0tLS0tLS0tLS06fDotLS0tLS0tLS0tLS0tLS0tOnwKfCBgbWFya2Rvd25gICAgICAgICAgICAgICAgICAgICB8IHNtYWxsICAgICAgICAgICAgfCBtaW5pbWFsICAgICAgICAgICAgICB8IGJlZ2lubmVyICAgICAgICAgfAp8IGBybWFya2Rvd246OnBhZ2VkX3RhYmxlYCAgICAgIHwgbGFyZ2UgICAgICAgICAgICB8IG1pbmltYWwgICAgICAgICAgICAgIHwgYmVnaW5uZXIgICAgICAgICB8CnwgYGtuaXRyOjprYWJsZWAgKyBga2FibGVFeHRyYWAgfCBzbWFsbCAgICAgICAgICAgIHwgZXh0ZW5zaXZlICAgICAgICAgICAgfCBpbnRlcm1lZGlhdGUgICAgIHwKfCBgRFRgICsgYERhdGFUYWJsZXNgICAgICAgICAgICB8IGxhcmdlICAgICAgICAgICAgfCBleHRlbnNpdmUgICAgICAgICAgICB8IGFkdmFuY2VkICAgICAgICAgfApUYWJsZTogKlRhYmxlIHR5cGVzIGFuZCByZWNvbW1lbmRlZCB1c2VzLioKCjxici8+CgojIyMgMi4xIE1hcmtkb3duCgpUaGUgc2ltcGxlc3QgbWV0aG9kIG9mIGJ1aWxkaW5nIGEgdGFibGUgaXMgd2l0aCBNYXJrZG93biBzeW50YXguIFRoaXMgaXMgYSBuaWNlIG9wdGlvbiBiZWNhdXNlIHlvdSBjYW4gaGFyZCBjb2RlIHRoZSB0YWJsZSByaWdodCBpbnRvIHRoZSBkb2N1bWVudC0tLW5vIG5lZWQgdG8gaW5zdGFsbCBhbmQgbG9hZCBsaWJyYXJpZXMgb3Igd3JpdGUgY29kZSBjaHVua3MtLS1hbmQgaXQgaXMgZWFzeSB0byBpbXBsZW1lbnQuIFRoZSBkb3duc2lkZSBpcyB0aGVyZSBpcyBtaW5pbWFsIGZ1bmN0aW9uYWxpdHkgYXZhaWxhYmxlIGluIGEgTWFya2Rvd24gdGFibGUuCgpNYXJrZG93biBkb2VzIG5vdCB3b3JrIHdlbGwgZm9yIGxhcmdlIHRhYmxlcy4gU28gSSB3aWxsIGZpcnN0IGdyYWIgYSBzdWJzZXQgb2YgYG10Y2Fyc2AsIHNwZWNpZmljYWxseSB0aGUgZmlyc3QgNCByb3dzIGFuZCAzIGNvbHVtbnMuIEluIG15IGNvZGUgY2h1bmsgSSBhZGQgdGhlIGNodW5rIG9wdGlvbiBgY29tbWVudD0iImAuIFRoaXMgcHJldmVudHMga25pdCBmcm9tIGFwcGVuZGluZyBhIHN0cmluZyAoZGVmYXVsdCBpcyBgIyNgKSB0byB0aGUgc3RhcnQgb2YgZWFjaCBsaW5lIG9mIHJlc3VsdHMgaW4gdGhlIGZpbmFsIGRvY3VtZW50LgoKYGBge3IgbXRjYXJzX3N1YiwgY29tbWVudD0iIn0KbXRjYXJzX3N1YiA8LSBtdGNhcnNbMTo0LDE6M10KbXRjYXJzX3N1YgpgYGAKCjxici8+CgoqSW5jaWRlbnRhbGx5LCB0aGUgcmVzdWx0cyBib3ggYWJvdmUgaXMgdGVjaG5pY2FsbHkgdGhlIHNpbXBsZXN0IHRhYmxlIHlvdSBjYW4gbWFrZSwgZWl0aGVyIGJ5IGNhbGxpbmcgdGhlIGRhdGEgZnJhbWUgYG10Y2Fyc19zdWJgIGRpcmVjdGx5IG9yIHJ1bm5pbmcgYHByaW50LmRhdGEuZnJhbWUobXRjYXJzX3N1YilgLioKCkFueXdheSwgcnVuIHRoaXMgY29kZSBjaHVuaywgY29weSB0aGUgcmVzdWx0cywgYW5kIG1ha2UgYSBNYXJrZG93biB0YWJsZS4gWW91IGNhbiBlaXRoZXIgcnVuIHRoZSBjaHVuayBpbiBSU3R1ZGlvIHdpdGhvdXQgcmVuZGVyaW5nIHRoZSBkb2N1bWVudCAoZGVzY3JpYmVkIGFib3ZlKSBvciByZW5kZXIgdGhlIGRvY3VtZW50IGFuZCBjb3B5IHRoZSByZXN1bHRzIGZyb20gSFRNTCBwYWdlLiBJIGFkZGVkIGEgaGVhZGVyIHRvIHRoZSBmaXJzdCBjb2x1bW4uIEFuZCBoZXJlIGlzIHRoZSBNYXJrZG93biB0YWJsZS4KCjxici8+Cgp8IG1vZGVsICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgIG1wZyAgIHwgIGN5bCB8ICBkaXNwICAgICB8Cnw6LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tfDotLS0tLS06fDotLS0tOnwtLS0tLS0tLS0tOnwKfCBbTWF6ZGEgUlg0XShodHRwczovL3Njby53aWtpcGVkaWEub3JnL3dpa2kvTWF6ZGFfUlgtNCkgICAgICAgICAgICB8ICoyMS4wKiB8ICoqNioqfCAgICAxNjAgICAgfAp8IGBNYXpkYSBSWDQgV2FnYCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHwgKjIxLjAqIHwgICA2ICB8ICAgIDE2MCAgICB8CnwgW0RhdHN1biA3MTBdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL05pc3Nhbl9WaW9sZXQjNzEwKSAgICAgfCAqMjIuOCogfCAgIDQgIHwgICAgMTA4ICAgIHwKfCBbSG9ybmV0IDQgRHJpdmVdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0FNQ19Ib3JuZXQpICAgICAgICB8IDIxLjQgICB8ICAgNiAgfCAgKioyNTgqKiAgfApUYWJsZTogICpEZW1vbnN0cmF0aW9uIG9mIHRoZSBvdXRwdXQgZnJvbSBgcGlwZV90YWJsZXNgIE1hcmtkb3duIHN5bnRheC4qCgo8YnIvPgoKU2luY2UgdGhpcyBpcyBhIE1hcmtkb3duIHRhYmxlLCB5b3UgY2FuIGFkZCBhZGRpdGlvbmFsIE1hcmtkb3duIHN5bnRheCBmb3IgZm9ybWF0dGluZy4gU2VlIGlmIHlvdSBjYW4gZmlndXJlIG91dCB3aGF0IHN5bnRheCBJIGFkZGVkIHRvIG15IHRhYmxlIGFuZCBhZGQgc29tZSB0byB5b3VyIHRhYmxlLiBBbHNvIGNoZWNrIG91dCB0aGUgKlRhYmxlcyogc2VjdGlvbiBvZiBbUGFuRG9jIFVzZXIncyBHdWlkZV0oaHR0cHM6Ly9wYW5kb2Mub3JnL01BTlVBTC5odG1sI3RhYmxlcykgZm9yIG90aGVyIE1hcmtkb3duIHRhYmxlIG9wdGlvbnMsIGluY2x1ZGluZyBob3cgdG8gYWRkIGEgY2FwdGlvbi4gSW4gYWRkaXRpb24gdG8gYHBpcGVfdGFibGVzYCwgeW91IGNhbiBjcmVhdGUgYG11bHRpbGluZV90YWJsZXNgIGBncmlkX3RhYmxlc2AsIGFuZCBgc2ltcGxlX3RhYmxlc2AuCgpTb21ldGhpbmcgdG8gbm90aWNlIGlzIHRoYXQgdGhlIE1hcmtkb3duIHRhYmxlIHNwYW5zIHRoZSBlbnRpcmUgd2lkdGggb2YgdGhlIHBhZ2UtLS1ldmVuIHRob3VnaCBpdCBkb2VzIG5vdCBuZWVkIGFsbCBvZiB0aGF0IHNwYWNlLiBBcyBmYXIgYXMgSSBrbm93LCB0aGVyZSBpcyBubyB3YXkgdG8gY29udHJvbCB0aGlzIGJlaGF2aW9yIHdpdGhvdXQgYWRkaW5nIGFkZGl0aW9uYWwgSFRNTCBmb3JtYXR0aW5nLgoKPiAqKlJlY29tbWVuZGF0aW9uKiogVXNlIGBNYXJrZG93bmAgZm9yIHNtYWxsLCBzaW1wbGUgdGFibGVzIHdoZXJlIHN0eWxpbmcgaXMgbm90IGEgY29uY2Vybi4KCiMjIyAyLjIgUiBNYXJrZG93biBQYWdlZCBUYWJsZXMKCldpdGggbGFyZ2VyIHRhYmxlcywgaXQgbWF5IG5vdCBiZSBwcmFjdGljYWwgdG8gZGlzcGxheSB0aGUgZnVsbCB0YWJsZSBpbmxpbmUuIFNvIHdlIG5lZWQgYSB3YXkgdG8gc2hyaW5rIGEgbGFyZ2UgdGFibGUgc28gaXQgbG9va3MgZ29vZCB3aGlsZSBzdGlsbCBhbGxvd2luZyBhY2Nlc3MgdG8gdGhlIGZ1bGwgdGFibGUuCgpUaGUgbmV4dCB0eXBlIG9mIHRhYmxlIEkgd2FudCB5b3UgdG8gdHJ5IGFyZSBQYWdlZCBUYWJsZXMuIFIgTWFya2Rvd24gY29tZXMgd2l0aCBpdHMgb3duIGJ1aWx0IGluIHRhYmxlIGZ1bmN0aW9uIGNhbGxlZCBgcGFnZWRfdGFibGVgLiBUaGUgYHBhZ2VkX3RhYmxlYCBmdW5jdGlvbiBhbGxvd3MgcGFnaW5hdGlvbiBvZiByb3dzIGFuZCBjb2x1bW5zIG1ha2luZyBpdCBwb3NzaWJsZSB0byByZW5kZXIgYSBsYXJnZSB0YWJsZSBpbiBhIHNtYWxsIHNwYWNlLgoKSXQgaXMgZWFzeSB0byBjb2RlIGBwYWdlZF90YWJsZWAgYnV0IHRoYXQgZWFzZSBjb21lcyB3aXRoIGEgc21hbGwgcHJpY2UtLS1saW1pdGVkIGZ1bmN0aW9uYWxpdHkuIEhlcmUgYXJlIHRoZSBvcHRpb25zIHlvdSBkbyBoYXZlIHdpdGggYHBhZ2VkX3RhYmxlYCBmdW5jdGlvbi4KCnwgT3B0aW9uICAgICAgICAgICB8IERlc2NyaXB0aW9uICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfAp8LS0tLS0tLS0tLS0tLS0tLS0tfC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLXwKfCBgcm93cy5wcmludGAgICAgIHwgTWF4aW11bSByb3dzIHRvIHByaW50IHBlciBwYWdlLiAgICAgICAgICAgICAgICB8CnwgYG1heC5wcmludGAgICAgICB8IE1heGltdW0gcm93cyBpbiB0aGUgdGFibGUgKGRlZmF1bHRzIHRvIDEwMDApLiAgfAp8IGBjb2xzLnByaW50YCAgICAgfCBNYXhpbXVtIGNvbHVtbnMgaW4gdGhlIHRhYmxlIChkZWZhdWx0cyB0byAxMCkuIHwKfCBgcm93bmFtZXMucHJpbnRgIHwgUHJpbnQgcm93IG5hbWVzIGFzIHBhcnQgb2YgdGhlIHRhYmxlLiAgICAgICAgICB8ClRhYmxlOiAqQSBNYXJrZG93biB0YWJsZSBsaXN0aW5nIHRoZSBPcHRpb25zIGZvciB0aGUgYHBhZ2VkX3RhYmxlYCBmdW5jdGlvbi4gKgoKKioqQSBxdWljayBzaWRlIG5vdGUqKiouIFlvdSBhY3R1YWxseSBuZWVkIHRvIGxvYWQgdGhlIGBybWFya2Rvd25gIHBhY2thZ2UgZm9yIGBwYWdlZF90YWJsZWAgdG8gd29yay4gQW55d2F5LCB0aGlzIGlzIGEgZ29vZCB0aW1lIHRvIHJldHVybiB0byB0aGUgZmlyc3QgY29kZSBjaHVuayBpbiB5b3VyIGAuUm1kYCBmaWxlLS0tdGhlIGNodW5rIGNhbGxlZCBgc2V0dXBgIHRoYXQgUiBNYXJrZG93biBhZGRlZCBieSBkZWZhdWx0LgoKSSBsaWtlIHRvIHVzZSB0aGlzIGNodW5rIHRvIGxvYWQgYWxsIG9mIHRoZSBwYWNrYWdlcyBJIG5lZWQgZm9yIG15IGRvY3VtZW50LiBVc2luZyBhIHNpbmdsZSBjaHVuayBmb3IgYWxsIG9mIG15IHBhY2thZ2VzIGhlbHBzIG1lIGtlZXAgbXkgZG9jdW1lbnQgb3JnYW5pemVkLiBOb3RpY2UgdGhlIGBzZXR1cGAgY2h1bmsgaGFzIHRoZSBvcHRpb24gYGluY2x1ZGU9RkFMU0VgLiBUaGlzIHByZXZlbnRzIHRoZSBjb250ZW50IG9mIHRoZSBjaHVuayBmcm9tIGFwcGVhcmluZyBpbiB0aGUgZmluYWwgZG9jdW1lbnQsIHdoaWNoIGZvciBtZSBpcyBtb3JlIHN0eWxpc3RpY2FsbHkgYXBwZWFsaW5nLiAgSSBjYW4gYWRkIGEgYHNlc3Npb25JbmZvKClgIGNodW5rIGF0IHRoZSBlbmQgb2YgbXkgZG9jdW1lbnQgdG8gcmVwb3J0IGFsbCBvZiB0aGUgcGFja2FnZXMgc28gdGhpcyBpbmZvcm1hdGlvbiBpcyBhdmFpbGFibGUgdG8gdGhlIHJlYWRlci4gV2Ugd2lsbCBjb3ZlciBgc2Vzc2lvbkluZm8oKWAgd2hlbiB3ZSBnZXQgaW50byBtb3JlIGRlcHRoIG9uIHRoZSBzdWJqZWN0IG9mICpyZXByb2R1Y2libGUqLiBJZiB5b3UgZG8gbm90IHdhbnQgdG8gbG9hZCB0aGUgbGlicmFyeSB5b3UgY2FuIHJ1biB0aGUgY29tbWFuZCBsaWtlIHRoaXM6IGBybWFya2Rvd246OnBhZ2VkX3RhYmxlKClgLgoKKioqT0ssIGJhY2sgdG8gdGhlIHRhYmxlKioqLiBOb3cgSSBjYW4gY3JlYXRlIGEgdGFibGUgb2YgYG10Y2Fyc2Agd2l0aCB0aGUgYHBhZ2VkX3RhYmxlYCBmdW5jdGlvbiBhbmQgdXNlIGFuIG9wdGlvbiB0byBsaW1pdCB0aGUgbnVtYmVyIG9mIHByaW50ZWQgcm93cyB0byBgNWAgZm9yIGVhY2ggcGFnZS4gSSB1c2VkIGBlY2hvPUZBTFNFYCBpbiBteSBjb2RlIGNodW5rIHRvIGhpZGUgdGhlIGNvZGUgOikuIEJ5IG5vdyB5b3Ugc2hvdWxkIGtub3cgd2hlcmUgdG8gbG9vayBmb3IgYSBzb2x1dGlvbi4KCjxici8+CgpgYGB7ciBtdGNhcnNfcGFnZWQsIGVjaG89RkFMU0UsIGZpZy5jYXA9InN0dWZmIn0KcGFnZWRfdGFibGUobXRjYXJzLCBvcHRpb25zID0gbGlzdChyb3dzLnByaW50ID0gNSkpCmBgYAoKTm90aWNlIHRoYXQgZm9yIGVhY2ggY29sdW1uLCB0aGUgY29sdW1uICpjbGFzcyogaXMgcHJpbnRlZCBiZWxvdyB0aGUgbmFtZSAodGV4dCBlbmNsb3NlZCBpbiA8ID4pLiBUaGlzIGlzIGlycml0YXRpbmcgYW5kIHJlbGF0ZWQgdG8gcHJpbnRpbmcgYSB0YWJsZSBmcm9tIGEgYnVpbHQtaW4gZGF0YSBmcmFtZS4gSSBoYXZlIG5vIGlkZWEgaG93IHRvIGZpeCB0aGlzICh3aXRoaW4gdGhlIGNvbmZpbmVzIG9mIFIgTWFya2Rvd24pIGJ1dCBJIHdpbGwgd29yayBvbiBhIHNvbHV0aW9uLgoKPiAqKlJlY29tbWVuZGF0aW9uKiogVXNlIGBwYWdlZF90YWJsZWAgZm9yIGxhcmdlIHRhYmxlcyB3aGVyZSBleHRlbnNpdmUgc3R5bGluZyBpcyBub3QgYSBjb25jZXJuLgoKIyMjIDIuMyBLYWJsZSBUYWJsZXMKCktuaXRyIGNvbWVzIHdpdGggaXRzIG93biB0b29sIGZvciByZW5kZXJpbmcgc2ltcGxlIHRhYmxlcyBjYWxsZWQgYGthYmxlYC4gVGhlIGRvY3VtZW50YXRpb24gZm9yIGBrYWJsZWAgY2FuIGJlIGZvdW5kIFtoZXJlXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMva2FibGVFeHRyYS9pbmRleC5odG1sKSBvciBieSBydW5uaW5nIGA/a25pdHI6OmthYmxlKClgIGluIHRoZSBDb25zb2xlLiBCeSBpdHNlbGYsIGthYmxlICBjb21lcyB3aXRoICphbG1vc3Qgbm8gb3B0aW9ucyouIFdlIGNhbiBleHRlbmQgaXRzIGZ1bmN0aW9uYWxpdHkgd2l0aCB0aGUgYGthYmxlRXh0cmFgIHBhY2thZ2UgYW5kIHBpcGluZyBzeW50YXggZnJvbSBgbWFncml0dHJgLiBUaGUgZmVhdHVyZXMgb2YgYGthYmxlRXh0cmFgICBhcmUgZXh0ZW5zaXZlIGFuZCBJIHdpbGwgb25seSB0b3VjaCBvbiBhIGZldyBoZXJlLiBUaGUgZG9jdW1lbnRhdGlvbiBmb3IgYGthYmxlRXh0cmFgIGNhbiBiZSBmb3VuZCBbaGVyZV0oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL2thYmxlRXh0cmEvaW5kZXguaHRtbCkgb3IgYnkgcnVubmluZyBgP2thYmxlRXh0cmFgIGluIHRoZSBDb25zb2xlIGFmdGVyIHRoZSBwYWNrYWdlIGhhcyBiZWVuIGluc3RhbGxlZCBhbmQgbG9hZGVkLgoKPiBJIGhpZ2hseSByZWNvbW1lbmQgeW91IFtsZWFybiBob3cgdG8gdXNlIHRoZXNlIHBhY2thZ2VzXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMva2FibGVFeHRyYS92aWduZXR0ZXMvYXdlc29tZV90YWJsZV9pbl9odG1sLmh0bWwpIGZvciBtYWtpbmcgdGFibGVzLgoKQWdhaW4sIHlvdSB3aWxsIG5lZWQgdG8gbG9hZCBga2FibGVFeHRyYWAgYW5kIGVpdGhlciBsb2FkIHRoZSBga25pdHJgIHBhY2thZ2Ugb3IgcnVuIHRoZSBjb21tYW5kIGxpa2UgdGhpczogYGtuaXRyOjprYWJsZSgpYC4KCkZpcnN0LCBsZXTigJlzIGxvb2sgYXQgdGhlIGRlZmF1bHQgYGthYmxlYCB0YWJsZSBvdXRwdXQuIFdlIHdpbGwgdXNlIHRoZSBoZWFkIG9mIHRoZSBgbXRjYXJzYCBkYXRhIHNldC4KCjxici8+CgpgYGB7ciBrYWJsZV9kZWZhdWx0fQprYWJsZShoZWFkKG10Y2FycyksIGNhcHRpb24gPSAiKldvdywgdGhpcyB0YWJsZSBsb29rcyB0ZXJyaWJsZS4qIikKYGBgCgo8YnIvPgoKSWYgd2UgdHJpZWQgdG8gcmVuZGVyIHRoZSBlbnRpcmUgdGFibGUgYnkgb21pdHRpbmcgYGhlYWRgLCB3ZSB3b3VsZCBqdXN0IGdldCBhIGxvbmcsIGNyYXBweSB0YWJsZSBpbiBvdXIgZG9jdW1lbnQuIE5vdCBjb29sLiBMZXRzIHNlZSBpZiB3ZSBjYW4gamF6eiB0aGlzIHVwIGEgYml0IHdpdGggYGthYmxlRXh0cmFgLgoKYGBge3Iga2FibGVfamF6en0Ka2FibGUoaGVhZChtdGNhcnMpLCBjYXB0aW9uID0gIipUaGlzIHRhYmxlIGxvb2tzIGJldHRlcioiKSAlPiUKICBrYWJsZV9zdHlsaW5nKCkKCmBgYAoKSGVyZSBJIHVzZWQgdGhlIFtwaXBlIG9wZXJhdG9yXShodHRwczovL3JpcHR1dG9yaWFsLmNvbS9yL3RvcGljLzY1Mi9waXBlLW9wZXJhdG9ycy0tLS0tLWFuZC1vdGhlcnMtKSAoYCU+JWApIHRvIHBhc3MgdGhlIHJlc3VsdHMgb2YgYGthYmxlYCB0byB0aGUgZnVuY3Rpb24gYGthYmxlX3N0eWxpbmdgLS0tYSBwYXJ0IG9mIHRoZSBga2FibGVFeHRyYWAgcGFja2FnZS4gQnkgcnVubmluZyAgYGthYmxlX3N0eWxpbmdgICphcyBpcyosIEkgYW0gdXNpbmcgZGVmYXVsdHMgZm9yIGFsbCBvZiB0aGUgb3B0aW9ucy4KCj4gVGhlIHBpcGUgb3BlcmF0b3IgaXMgYSBwb3dlcmZ1bCB0b29sIHdvcnRoIGxlYXJuaW5nLgoKQmFjayB0byB0aGUgdGFibGUuIEl0IGNlcnRhaW5seSBsb29rcyBiZXR0ZXIgdGhhbiB0aGUgZGVmYXVsdCBga2FibGVgIHZlcnNpb24gYnV0IHdlIGFyZSBtaXNzaW5nIHRoZSBhYmlsaXR5IHRvICpwYWdlKiB0aGUgdGFibGUuIEkgd291bGQgbGlrZSB5b3UgdG8gcnVuIHRoZXNlIHR3byBjb21tYW5kcyBhbmQgbG9vayBhdCB0aGUgb3V0cHV0LgoKVGhpcyBjb21tYW5kIHdpbGwgaW5jbHVkZSB0aGUgd2hvbGUgdGFibGUuCgpgYGAKa2FibGUobXRjYXJzKSAlPiUKICBrYWJsZV9zdHlsaW5nKCkKYGBgCgpBbmQgdGhpcyBjb21tYW5kIHdpbGwgdHJhbnNwb3NlIHRoZSB0YWJsZSAoc3dhcCByb3dzIGFuZCBjb2x1bW5zKSB1c2luZyB0aGUgdHJhbnNwb3NlIChgdGApIGZ1bmN0aW9uLiBSZW1lbWJlciwgYG10Y2Fyc2AgaGFzIGByIG5yb3cobXRjYXJzKWAgcm93cyBhbmQgYHIgbmNvbChtdGNhcnMpYCBjb2x1bW5zIGJ1dCB3aGVuIHlvdSB0cmFuc3Bvc2UgdGhlIHRhYmxlLCBpdCBoYXMgYHIgbnJvdyh0KG10Y2FycykpYCByb3dzIGFuZCBgciBuY29sKHQobXRjYXJzKSlgIGNvbHVtbnMuIFNvIGl0IGlzIHJlYWxseSB3aWRlIGluIHRoZSB0cmFuc3Bvc2VkIHN0YXRlLgoKYGBgCmthYmxlKGhlYWQodChtdGNhcnMpKSkgJT4lCiAga2FibGVfc3R5bGluZygpCmBgYAoKSSBob3BlIHlvdSBhZ3JlZSB0aGF0IG5laXRoZXIgb2YgdGhlc2UgdGFibGVzIGFyZSBhY2NlcHRhYmxlLCBlc3BlY2lhbGx5IHRoZSBzZWNvbmQgb25lLiBVbmZvcnR1bmF0ZWx5LCB0aGUgYGthYmxlRXh0cmFgIHBhY2thZ2UgZG9lcyBub3QgY29tZSB3aXRoIGFuIG9wdGlvbiB0byBhZGQgcGFnaW5hdGlvbi4gWW91IGNhbiBob3dldmVyIHB1dCB0aGUgdGFibGUgaW4gYSBmaXhlZC1oZWlnaHQsIGZpeGVkLXdpZHRoIChvciBib3RoKSBib3gsIGFuZCBtYWtlIGl0IHNjcm9sbGFibGUuIFdlIGNhbiBkbyB0aGlzIGJ5IHVzaW5nIGEgcGlwZSBvcGVyYXRvciBhbmQgdGhlIGBzY3JvbGxfYm94YCBmdW5jdGlvbi4gV2hpbGUgd2UgYXJlIGF0IGl0LCBsZXRzIGFsc28gYWRkIHR3ZWFrIHNvbWUgb3B0aW9ucyBpbiBga2FibGVfc3R5bGluZ2AgdG8gbWFrZSBhIG1vcmUgaGFuZHNvbWUgdGFibGUuCgpgYGB7ciBrYWJsZV9zY3JvbGx9CmthYmxlKHQobXRjYXJzKSwgY2FwdGlvbiA9ICIqU2Nyb2xsYWJsZSBrYWJsZSB0YWJsZS4qIikgJT4lCiAga2FibGVfc3R5bGluZyhib290c3RyYXBfb3B0aW9ucyA9IGMoInN0cmlwZWQiLCAiaG92ZXIiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjb25kZW5zZWQiLCAicmVzcG9uc2l2ZSIpKSAlPiUKICBzY3JvbGxfYm94KHdpZHRoID0gIjEwMCUiLCBoZWlnaHQgPSAiMzAwcHgiKQpgYGAKCjxici8+CgpGb3IgdGhlIGBzY3JvbGxfYm94YCBmdW5jdGlvbiBJIHNldCB0aGUgYHdpZHRoID0gIjEwMCUiYCByYXRoZXIgdGhhbiBzcGVjaWZ5aW5nIGEgZGltZW5zaW9uLiBUaGlzIGVuc3VyZXMgdGhlIGJveCB3aWxsIGFsd2F5cyBiZSB0aGUgd2lkdGggb2YgdGhlIHBhZ2Ugbm8gbWF0dGVyIGhvdyBzbWFsbCB0aGUgd2luZG93IGlzLgoKRXZlbiB0aG91Z2ggeW91IGNhbm5vdCBtYWtlIGEgcGFnZWQgdGFibGUgd2l0aCBga2FibGVgLCB0aGVyZSBhcmUgIG1hbnkgc3R5bGluZyBvcHRpb25zIGF2YWlsYWJsZSBpbiB0aGUgYGthYmxlRXh0cmFgIHBhY2thZ2UgdGhhdCBtYWtlcyB0aGlzIG1ldGhvZCAgZXh0cmVtZWx5IHVzZWZ1bCBhbmQgd29ydGggbGVhcm5pbmcuIFBsdXMsIHRoZSBjb2RlIGlzIHJlbGF0aXZlbHkgc2ltcGxlIHRvIHdyaXRlLgoKSSB3YW50IHRvIHNob3cgeW91IG9uZSBtb3JlIGZlYXR1cmUgdGhhdCBpcyBub3QgYXZhaWxhYmxlIHRoZSBvdGhlciB0YWJsZSBtZXRob2RzIHdlIGNvdmVyIGluIHRoaXMgQXNzaWdubWVudC0tLSpmbG9hdGluZyouIExldCdzIGZpcnN0IHN1YnNldCB0aGUgYG10Y2Fyc2AgZGF0YSBzZXQgc28gd2UgY2FuIG1ha2UgYSBzbWFsbCB0YWJsZS4gTmV4dCB3ZSB1c2UgdGhlIGBmdWxsX3dpZHRoYCBhbmQgYHBvc2l0aW9uYCBvcHRpb25zIHRvIGNvbnRyb2wgdGhlIHNpemUgYW5kIHBvc2l0aW9uIG9mIHRoZSB0YWJsZS4gCgpIZXJlIGlzIG91ciBjb2RlIGNodW5rLgoKYGBge3Iga2FibGVfZmxvYXR9Cm10Y2Fyc19zdWIgPC0gbXRjYXJzWzE6NywxOjZdCmthYmxlKG10Y2Fyc19zdWIpICU+JQogIGthYmxlX3N0eWxpbmcoYm9vdHN0cmFwX29wdGlvbnMgPSAic3RyaXBlZCIsCiAgICAgICAgICAgICAgICBmdWxsX3dpZHRoID0gRkFMU0UsCiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9ICJmbG9hdF9yaWdodCIpCmBgYAoKPGJyLz48YnIvPgoKTGV04oCZcyBzYXkgd2UgaGF2ZSBhIGJ1bmNoIG9mIHRleHQgdGhhdCB3ZSB3YW50IHRvIHB1dCBzaWRlLWJ5LXNpZGUgd2l0aCB0aGlzIHNtYWxsIHRhYmxlLiBPdXIgc3Vic2V0dGVkIGBtdGNhcnNgIGRhdGEgc2V0IG5vdyBoYXMgYHIgbnJvdyhtdGNhcnNfc3ViKWAgcm93cyBhbmQgYHIgbmNvbChtdGNhcnNfc3ViKWAgY29sdW1ucy4gV2UgY2FuIG1ha2Ugb3VyIHRhYmxlIHNtYWxsZXIgYnkgc2V0dGluZyBgZnVsbF93aWR0aCA9IEZBTFNFYCBpbiBga2FibGVfc3R5bGluZ2AgYW5kIGZsb2F0IHRoZSB0YWJsZSBieSBzZXR0aW5nIGBwb3NpdGlvbiA9ICJmbG9hdF9yaWdodCJgCgpQbGVhc2Ugc3R1ZHkgdGhlIFtleHRlbnNpdmUgb3B0aW9ucyBhdmFpbGFibGUgaW4gYGthYmxlYCBhbmQgYGthYmxlRXh0cmFgXShodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy93ZWIvcGFja2FnZXMva2FibGVFeHRyYS92aWduZXR0ZXMvYXdlc29tZV90YWJsZV9pbl9odG1sLmh0bWwpIGFuZCBjcmVhdGUgdGFibGVzIHRoYXQgaW1wbGVtZW50IHNvbWUgb2YgdGhlIG9wdGlvbnMuCgo8YnIvPjxici8+Cgo+ICoqUmVjb21tZW5kYXRpb24qKiBVc2UgYGthYmxlYCArIGBrYWJsZUV4dHJhYCBmb3Igc21hbGwgdGFibGVzIHdoZXJlIGV4dGVuc2l2ZSBzdHlsaW5nIGlzIGRlc2lyZWQuCgojIyMgMi40IERUIFRhYmxlcwoKVGhlIGxhc3Qgb3B0aW9uIEkgd2FudCB0byBjb3ZlciBmb3IgYnVpbGRpbmcgdGFibGVzIGlzIGltcGxlbWVudGVkIHVzaW5nIHRoZSBgZGF0YXRhYmxlYCBmdW5jdGlvbiBmcm9tIHRoZSBbRFRdKGh0dHBzOi8vcnN0dWRpby5naXRodWIuaW8vRFQvKSBwYWNrYWdlLCBhbiBpbnRlcmZhY2UgdG8gdGhlIEphdmFTY3JpcHQgbGlicmFyeSAqW0RhdGFUYWJsZXNdKGh0dHBzOi8vZGF0YXRhYmxlcy5uZXQvKSouIFRvIGRlbW9uc3RyYXRlIHRoZSBmdW5jdGlvbmFsaXR5LCBJIHdpbGwgdXNlIGEgbGFyZ2VyIGRhdGEgc2V0IGNhbGxlZCBgVVNKdWRnZVJhdGluZ3NgIGZyb20gdGhlIGBkYXRhc2V0c2AgcGFja2FnZS4gYFVTSnVkZ2VSYXRpbmdzYCBoYXMgYHIgbnJvdyhVU0p1ZGdlUmF0aW5ncylgIHJvd3MgYW5kIGByIG5jb2woVVNKdWRnZVJhdGluZ3MpYCBjb2x1bW5zLiBUaGlzIHRhYmxlIGlzIHRvbyBiaWctLS1ob3Jpem9udGFsbHkgYW5kIHZlcnRpY2FsbHktLS10byBmaXQgb24gYSBzdGFuZGFyZCBwYWdlLgoKVGhlIHN5bnRheCBmb3IgdGhlIGBEVDo6ZGF0YXRhYmxlYCBpcyBtb3JlIGNvbXBsaWNhdGVkIHRoYW4gdGhlIG90aGVyIG1ldGhvZHMgYnV0IHRoYXQgY29tZXMgd2l0aCAgbW9yZSBleHRlbnNpdmUgZnVuY3Rpb25hbGl0eS4KCj4gV29ya2luZyB3aXRoIGBEVDo6ZGF0YXRhYmxlYCBpcyBhbiBhZHZhbmNlZCBsZXZlbCBza2lsbC4gSSBoaWdobHkgcmVjb21tZW5kIHlvdSBsZWFybiBob3cgdG8gdXNlIHRoZSBwYWNrYWdlLCBidXQgaXQgd2lsbCB0YWtlICBwcmFjdGljZS4KClBsZWFzZSBtYWtlIHN1cmUgeW91IGFyZSBjb21mb3J0YWJsZSB3aXRoIHRoZSBvdGhlciBtZXRob2RzIGZpcnN0IGJlZm9yZSB0cnlpbmcgdG8gdXNlIGBEVDo6ZGF0YXRhYmxlYC4gSSBwcm9taXNlLCBpZiB5b3UgZG8gbm90IGtub3cgd2hhdCB5b3UgYXJlIGRvaW5nLCB0aGlzIHBhY2thZ2Ugd2lsbCBjYXVzZSBhIGxvdCBvZiBmcnVzdHJhdGlvbi4gVGhhdCBzYWlkLCBJIHVzZSBpdCBhbGwgdGhlIHRpbWUgYmVjYXVzZSBpdCBpcyBhd2Vzb21lLgoKTW92aW5nIG9uLiBJZiB3ZSBydW4gYERUYCBvbiB0aGUgYFVTSnVkZ2VSYXRpbmdzYCBkYXRhIHNldCB3aXRob3V0IGFueSBvcHRpb25zIHRoZSB0YWJsZSB3aWxsIHNwaWxsIG9mZiB0aGUgc2lkZSBvZiB0aGUgcGFnZS4gQWdhaW4sIG5vdCBjb29sLiBUcnkgdG8gcnVuIHRoaXMgY29tbWFuZCBhbmQgc2VlIHdoYXQgaGFwcGVucy4KCmBgYApkYXRhdGFibGUoVVNKdWRnZVJhdGluZ3MpCmBgYAoKYERUOjpkYXRhdGFibGVgICpkb2VzIG5vdCBwYWdlIHRhYmxlcyBob3Jpem9udGFsbHkqIGxpa2UgdGhlIGBwYWdlZF90YWJsZWAgY29tbWFuZCBkb2VzIChkZXNjcmliZWQgYWJvdmUpLiBXZSBjYW4gc2V0IHRoZSB3aWR0aCBvZiB0aGUgdGFibGUgYW5kIGFkZCBhbiBvcHRpb24gdGhhdCBhbGxvd3MgaG9yaXpvbnRhbCBzY3JvbGxpbmcuIEZvciB0aGlzIHdlIHVzZSB0aGUgYG9wdGlvbnNgIGFyZ3VtZW50LiBUaGUgc3ludGF4IGlzIHRvIGFkZCBgd2lkdGggPSAiMTAwJSJgIGZvbGxvd2VkIGJ5IGBvcHRpb25zID0gbGlzdCgpYCwgd2hlcmUgd2UgcHV0IGEgY29tbWEgc2VwYXJhdGVkIGxpc3Qgb2Ygb3B0aW9ucy4gRm9yIG5vdywgd2UganVzdCBpbmNsdWRlIGBzY3JvbGxYYCBpbiBvdXIgbGlzdCBvZiBvcHRpb25zLgoKYGBge3IgZHR9CmRhdGF0YWJsZShVU0p1ZGdlUmF0aW5ncywgd2lkdGggPSAiMTAwJSIsCiAgICAgICAgICBvcHRpb25zID0gbGlzdChzY3JvbGxYID0gVFJVRSkpCmBgYAoKPGJyLz4KClBsYXkgYXJvdW5kIHdpdGggdGhlIHRhYmxlIGEgbGl0dGxlLiBBcyB5b3UgY2FuIHNlZQoKKiB0aGUgdGFibGUgbm93IGZpdHMgaW4gdGhlIHdpbmRvdywKKiBob3Jpem9udGFsIHNjcm9sbGluZyBpbiBlbmFibGVkLAoqIHRoZSBwYWdlIGlzIHZlcnRpY2FsbHkgcGFnZWQsCiogdGhlcmUgaXMgYSAqU2hvdyBlbnRyaWVzKiBkcm9wIGRvd24sIGFuZAoqIHRoZXJlIGlzIGEgKlNlYXJjaCogYm94LgoKVGhlICpTaG93IGVudHJpZXMqIGFuZCAqU2VhcmNoKiBib3ggYXJlIGFkZGVkIGJ5IGRlZmF1bHQuIFdlIGNhbiBkZWNpZGUgd2hldGhlciB0byBzaG93IHRoZXNlIG9wdGlvbnMgb3Igbm90LiBJIHdpbGwgc2F2ZSB0aGF0IGZvciBsYXRlci4gRm9yIG5vdywgSSB3YW50IHRvIGxlYXZlIHlvdSB3aXRoIGEgbW9yZSBzdHlsaXplZCBEVCBkYXRhIHRhYmxlIHRvIGdpdmUgeW91IGEgc2Vuc2Ugb2YgdGhlIHBvc3NpYmlsaXRpZXMuIERvbid0IHdvcnJ5IHNvIG11Y2ggYWJvdXQgdGhlIGNvZGUtLS1wYXkgYXR0ZW50aW9uIHRvIHRoZSBmdW5jdGlvbmFsaXR5LgoKYGBge3IgZHRfamF6en0KZGF0YXRhYmxlKFVTSnVkZ2VSYXRpbmdzLCB3aWR0aCA9ICIxMDAlIiwKICAgICAgICAgIGV4dGVuc2lvbnMgPSAnQnV0dG9ucycsIG9wdGlvbnMgPSBsaXN0KAogICAgICAgICAgICBzY3JvbGxYID0gVFJVRSwKICAgICAgICAgICAgZG9tID0gJ2xmcnRpcEInLAogICAgICAgICAgICBidXR0b25zID0gYygnY29weScsICdjc3YnLCAnZXhjZWwnLCAncGRmJywgJ3ByaW50JyksCiAgICAgICAgICAgIHBhZ2VMZW5ndGggPSA1LAogICAgICAgICAgICBsZW5ndGhNZW51ID0gYyg1LCAxMCwgMjAsIDQ1KQogICAgICAgICAgICApCiAgICAgICAgICApCmBgYAo8YnIvPjxici8+CgpJIGFkZGVkIGJ1dHRvbnMgdG8gZG93bmxvYWQgdGhlIHRhYmxlIHRvIGRpZmZlcmVudCBmb3JtYXRzLCBjaGFuZ2VkIHRoZSBwYWdlIGxlbmd0aCB0byA1LCBhbmQgY2hhbmdlZCB0aGUgdmFsdWVzIGluIHRoZSAqU2hvdyBlbnRyaWVzKiBkcm9wIGRvd24uIFBsYXkgYXJvdW5kIHdpdGggdGhlIHRhYmxlLiBUaGVyZSBpcyBhIGxvdCBtb3JlIHRvIGRvIHdpdGggdGhpcyBwYWNrYWdlIGFuZCB3ZSB3aWxsIGNvbWUgYmFjayB0byBpdCBvZnRlbi4KCj4gKipSZWNvbW1lbmRhdGlvbioqIFVzZSBgRFQ6OmRhdGF0YWJsZWAgZm9yIGxhcmdlIHRhYmxlcyB3aGVyZSBleHRlbnNpdmUgc3R5bGluZyBpcyBkZXNpcmVkLgoKVGhhdOKAmXMgYWxsIGZvciB0aGlzIGFzc2lnbm1lbnQuIAoKIyMgQXNzaWdubWVudCAzOiBDb2RlCgpJZiB5b3UgYXJlIGludGVyZXN0ZWQgaW4gbWFraW5nIHlvdXIgc2NpZW5jZSBtb3JlIHRyYW5zcGFyZW50IGFuZCByZXByb2R1Y2libGUsIHlvdSBuZWVkIHRvIHByb3ZpZGUgYXQgbGVhc3QgdHdvIHRoaW5ncy0tLXRoZSByYXcgZGF0YSB5b3UgZ2VuZXJhdGVkIGFuZCB0aGUgY29kZSB5b3UgdXNlZCB0byBhbmFseXplIGl0LiBIb3BlZnVsbHkgaXQgaXMgb2J2aW91cyBieSBub3cgdGhhdCB5b3UgbmVlZCB0byBwcm92aWRlIGFjY2VzcyB0byAqKipib3RoKioqIGNvbXBvbmVudHM7IG5laXRoZXIgaXMgcGFydGljdWxhcmx5IHVzZWZ1bCB3aXRob3V0IHRoZSBvdGhlci4gV2Ugd2lsbCBjb3ZlciBkYXRhIGF2YWlsYWJpbGl0eSBpbiBhIGZ1dHVyZSBsZXNzb24uIEZvciB0aGlzIGFzc2lnbm1lbnQsIHlvdSB3aWxsIHByYWN0aWNlIHNldmVyYWwgZGlmZmVyZW50IG1ldGhvZHMgZm9yIG1ha2luZyB5b3VyIGNvZGUgYWNjZXNzaWJsZS4gVGhlIG1ldGhvZCBvciBtZXRob2RzIHlvdSBjaG9vc2UgZm9yIHlvdXIgb3duIHdvcmsgd2lsbCBkZXBlbmQgb24gdGhlIHR5cGUgb2YgYW5hbHlzZXMgKmFuZCogdGhlIHR5cGUgb2YgY29kZS4gCgo+IFlvdXIgYXNzaWdubWVudCBpcyB0byBpbXBsZW1lbnQgdGhlc2UgbWV0aG9kcyBpbiB5b3VyIGRvY3VtZW50IGFuZCBwbGF5IGFyb3VuZCB3aXRoIHRoZSBkaWZmZXJlbnQgb3B0aW9ucy4gCgojIyMgUHVybAoKS25pdHIgY29tZXMgd2l0aCBhIGJ1aWx0LWluIGZ1bmN0aW9uIGNhbGxlZCBgcHVybGAsIHdoaWNoIGFsbG93cyB5b3UgdG8gZXh0cmFjdCBhbGwgdGhlIFIgY29kZSBmcm9tIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQgYW5kIGNvbnZlcnQgaXQgdG8gYW4gUiBzY3JpcHQuIEluIG9yZGVyIHRvIHJ1biBgcHVybGAsIHlvdSBtdXN0IGVpdGhlciBsb2FkIHRoZSBrbml0ciBsaWJyYXJ5IGZpcnN0IChpLmUuLCBgbGlicmFyeShrbml0cilgKSBhbmQgdGhlbiBydW4gYHB1cmxgIG9yIGNhbGwgdGhlIGZ1bmN0aW9uIGRpcmVjdGx5IGJ5IHJ1bm5pbmcgYGtuaXRyOjpwdXJsKClgLiBXZSB3aWxsIHN0YXJ0IGJ5IGRpc2N1c3Npbmcgc29tZSBzaW1wbGUgKm9wdGlvbnMqIGZvciBydW5uaW5nIGBwdXJsYCBhbmQgdGhlbiB0YWxrIGFib3V0ICpob3cqIHlvdSBydW4gdGhlIGNvbW1hbmQuIFRoZSBiYXNpYyBzdHJ1Y3R1cmUgb2YgdGhlIGNvbW1hbmQgaXM6Cgo+IGBrbml0cjo6cHVybChpbnB1dD0iZmlsZW5hbWUuUm1kIiwgZG9jdW1lbnRhdGlvbiA9IEwpYAoKQnkgZGVmYXVsdCwgYHB1cmxgIHVzZXMgdGhlIGJhc2UgbmFtZSBvZiB0aGUgaW5wdXQgZmlsZSBhcyB0aGUgYmFzZSBuYW1lIG9mIHRoZSBvdXRwdXQgZmlsZS4gSWYgeW91IHdhbnQgdG8gY29udHJvbCB0aGlzIGJlaGF2aW9yLCBhZGQgdGhlIG9wdGlvbiBgb3V0cHV0PSJmaWxlbmFtZS5SImAgd2hlcmUgYGZpbGVuYW1lYCBpcyB3aGF0ZXZlciB5b3UgY2hvb3NlLiAKClRoZSBvcHRpb24gYGRvY3VtZW50YXRpb25gIGlzIGFuIGludGVnZXIgdGhhdCBzcGVjaWZpZXMgdGhlIGxldmVsIChgTGApIG9mIGRvY3VtZW50YXRpb24gdG8gYWRkIHRvIHRoZSBzY3JpcHQuIFlvdSBoYXZlIHRocmVlIGNob2ljZXMKCiogKiowKiogbWVhbnMgb3V0cHV0IHB1cmUgY29kZSB0byB0aGUgc2NyaXB0LCBkaXNjYXJkIGFsbCBNYXJrZG93biB0ZXh0IGFuZCBjb2RlIGNodW5rIGRldGFpbHMuIAoqICoqMSoqICh0aGUgZGVmYXVsdCkgbWVhbnMgZGlzY2FyZCBhbGwgTWFya2Rvd24gdGV4dCBidXQgYWRkIHRoZSBjaHVuayBoZWFkZXJzIHRvIHRoZSBzY3JpcHQgYXMgY29tbWVudGVkIGxpbmVzLiAKKiAqKjIqKiBtZWFucyB0byBhZGQgYWxsIE1hcmtkb3duIHRleHQgYW5kIGNvZGUgY2h1bmtzIHRvIHRoZSBzY3JpcHQgYXMgY29tbWVudGVkIGxpbmVzLgoKQXMgZmFyIGFzIEkga25vdywgeW91ICoqY2Fubm90KiogcnVuIGBwdXJsYCBmcm9tIGluc2lkZSBhbiBhY3R1YWwgY29kZSBjaHVuay4gSSBoYXZlIG5vIGlkZWEgd2h5IG5vciB3YXMgSSBhYmxlIHRvIGZpbmQgYW4gYW5zd2VyLiBJZiBoYXZlIGFuIGFuc3dlciBvciBrbm93IGEgc29sdXRpb24sIHBsZWFzZSBsZXQgdXMga25vdy4gVGhlcmUgKmVhc2llc3QqIHdheSB0byBnZW5lcmF0ZSBhbiBSIHNjcmlwdCBmcm9tIGFuIFIgTWFya2Rvd24gZG9jdW1lbnQgd2l0aCBgcHVybGAgdG8gIGlzIHRvIHJ1biB0aGUgY29tbWFuZCBpbiB0aGUgQ29uc29sZSBsaWtlIHNvOgoKYGtuaXRyOjpwdXJsKGlucHV0PSJmaWxlbmFtZS5SbWQiLCBkb2N1bWVudGF0aW9uID0gMSlgCgo+IFJ1biB0aGUgYHB1cmxgIGNvbW1hbmQgdXNpbmcgdGhlIHRocmVlIG9wdGlvbnMgZGVzY3JpYmVkIGFib3ZlIGZvciBgZG9jdW1lbnRhdGlvbmAgb3B0aW9uIGFuZCBsb29rIGF0IHRoZSBvdXRwdXQgZmlsZXMuIAoKSW5saW5lIFIgZXhwcmVzc2lvbnMgYXJlIGlnbm9yZWQgYnkgZGVmYXVsdC4gRm9yIGV4YW1wbGUsIGlmIHlvdSBoYWQgYW4gaW5saW5lIFIgZXhwcmVzc2lvbiBsaWtlIHRoaXMgYGAgYHIKc3FydCgyKWAgYGAgCnRoZSBleHByZXNzaW9uIHdvdWxkIG5vdCBiZSBpbmNsdWRlZCBpbiB0aGUgUiBzY3JpcHQgZ2VuZXJhdGVkIGJ5IGBwdXJsYC4gSWYgeW91IHdhbnQgdG8gaW5jbHVkZSBpbmxpbmUgZXhwcmVzc2lvbnMgaW4gdGhlIFIgc2NyaXB0LCB5b3UgbmVlZCB0byBzZXQgdGhlIGdsb2JhbCBSIG9wdGlvbiBga25pdHIucHVybC5pbmxpbmUgPSBUUlVFYCBiZWZvcmUgY2FsbGluZyBga25pdHI6OnB1cmwoKWAuIAoKUmVtZW1iZXIgd2F5IGJhY2sgd2hlbiB5b3UgZ2VuZXJhdGVkIHlvdXIgaW5pdGlhbCBSIE1hcmtkb3duIGRvY3VtZW50IGEgZGVmYXVsdCBjb2RlIGNodW5rIHdhcyBhZGRlZCBqdXN0IGJlbG93IHRoZSBZQU1MIGhlYWRlcj8KCgpgYGBgCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfWByICcnYAprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYApgYGBgCgpJZiB5b3UgYWRkIGBrbml0ci5wdXJsLmlubGluZSA9IFRSVUVgIHRvIHRoYXQgY29kZSBjaHVuaywgYWxsIGlubGluZSBleHByZXNzaW9ucyB3aWxsIGJlIGFkZGVkIHRvIHRoZSBSIHNjcmlwdC4gCgpgYGBgCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfWByICcnYAprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsIGtuaXRyLnB1cmwuaW5saW5lID0gVFJVRSkKYGBgCmBgYGAKClRoZSBsYXN0IHRoaW5nIEkgd2FudCB0byBtZW50aW9uIGlzIHRoYXQgeW91IGNhbiAqcHJldmVudCogY2VydGFpbiBjb2RlIGNodW5rcyBmcm9tIGFwcGVhcmluZyBpbiB0aGUgUiBTY3JpcHQgYnkgYWRkaW5nIHRoZSBvcHRpb24gYHB1cmwgPSBGQUxTRWAgdG8gdGhlIGNodW5rLiBGb3IgZXhhbXBsZSwgaWYgeW91IGFkZCB0aGlzIG9wdGlvbiB0byB0aGUgYHNldHVwYCBjaHVuayB3ZSBqdXN0IGRpc2N1c3NlZCB0aGF0IGNodW5rIHdpbGwgbm90IGFwcGVhciBpbiB0aGUgZmluYWwgZG9jdW1lbnQuICAKCmBgYGAKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIHB1cmwgPSBGQUxTRX1gciAnJ2AKa25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCBrbml0ci5wdXJsLmlubGluZSA9IFRSVUUpCmBgYApgYGBgCgpUZXN0IHRoZSBiZWhhdmlvciBvZiB0aGUgZGlmZmVyZW50IG9wdGlvbnMgZm9yIGBwdXJsYCBvbiB5b3VyIGRvY3VtZW50LiBZb3UgY2FuIGFsc28gdXNlIHRoaXMgZnVudGlvbiBvbiAqYW55KiBSIE1hcmtkb3duIGRvY3VtZW50IHRvIHF1aWNrbHkgcmV0cmlldmUgdGhlIGNvZGUuIEZvciBleGFtcGxlLCBpZiB5b3UgZG93bmxvYWQgdGhlIFJtZCBmaWxlIGZvciB0aGlzIHBhZ2UgZnJvbSBHaXRIdWIgeW91IGNhbiBydW4gYHB1cmxgIHRvIHF1aWNrbHkgZXh0cmFjdCB0aGUgUiBjb2RlLiAgCgo+ICoqUmVjb21tZW5kYXRpb24qKiBVc2UgYHB1cmxgIHRvIGdlbmVyYXRlIGEgc2ltcGxlIFIgc2NyaXB0IHZlcnNpb24gb2YgeW91ciBSIE1hcmtkb3duIGRvY3VtZW50ICphZnRlciogdGhlIGRvY3VtZW50IGlzIGZpbmlzaGVkIGFuZCBzYXZlZC4gWW91IGNhbiB0aGVuIGxpbmsgdG8gdGhlIGZpbGUgc29tZXdoZXJlIGluIHlvdXIgZG9jdW1lbnQuIAoKIyMjIERvd25sb2FkIFJtZAoKSSBob3BlIGJ5IG5vdyB5b3UgaGF2ZSBzZWVuIHRoYXQgYW55IGRvY3VtZW50IEkgcHJlc2VudCBpbiB0aGlzIGNvdXJzZSBoYXMgYSBsaW5rIHRvIGEgR2l0SHViIHJlcG8gd2hlcmUgeW91IGNhbiBkb3dubG9hZCBvciBjb3B5IHRoZSBgLlJtZGAgZmlsZS4gVGhhdCdzIGdyZWF0IGFuZCBhbGwsIGJ1dCB3b3VsZG4ndCBpdCBiZSBuaWNlIGlmIHlvdSBjb3VsZCBkbyBpdCByaWdodCBmcm9tIHRoZSBIVE1MIHBhZ2U/IFdlbGwsIHlvdSBjYW4gYnkgYWRkaW5nIG9uZSBzaW1wbGUgbGluZSBvZiBjb2RlIGFzIGEgcHJvcGVydHkgb2YgYGh0bWxfZG9jdW1lbnRgIGluIHlvdXIgWUFNTCBoZWFkZXIgLS0tYGNvZGVfZG93bmxvYWQ6IHRydWVgLiAKCmBgYApvdXRwdXQ6CiAgaHRtbF9kb2N1bWVudDoKICAgIHRoZW1lOiBqb3VybmFsCiAgICB0b2M6IHRydWUKICAgIHRvY19mbG9hdDogdHJ1ZQogICAgdG9jX2RlcHRoOiAzCiAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICBjb2RlX2Rvd25sb2FkOiB0cnVlCmBgYAoKWW91IGNvdWxkIG9mIGNvdXJzZSBzZXQgdGhlIHByb3BlcnR5IHRvIGBmYWxzZWAgZXhjZXB0IHRoaXMgaXMgdGhlIGRlZmF1bHQgdmFsdWUgYW5kIG5vdGhpbmcgd2lsbCBjaGFuZ2UuIExvb2sgYmFjayBhdCB0aGUgdG9wIG9mIHRoaXMgcGFnZSBhbmQgeW91IHNob3VsZCBub3cgc2VlIGEgYENvZGVgIGJ1dHRvbiBpbiB0aGUgdXBwZXIgcmlnaHQgY29ybmVyLiBDbGljayBvbiB0aGUgZHJvcCBkb3duIGFuZCBzZWxlY3QgYERvd25sb2FkIFJtZGAgYW5kIHRoaXMgZW50aXJlIHBhZ2Ugc2hvdWxkIGJlIHNhdmVkIHRvIHlvdXIgRG93bmxvYWRzIGRpcmVjdG9yeS4gCgo+IEdvIGFoZWFkIGFuZCBhZGQgdGhpcyBvcHRpb24gdG8geW91ciBZQU1MIGhlYWRlci4KCiMjIyBDb2RlIEZvbGRpbmcKCkkgaGF2ZSBtZW50aW9uZWQgYSB0aW1lIG9yIHR3byB0aGF0IHRoZSBiZW5lZml0cyBvZiB1c2luZyBSIE1hcmtkb3duIGlzIHRoZSBhYmlsaXR5IHRvICoqKmV4ZWN1dGUqKiogYW5kICoqKmRpc3BsYXkqKiogY29kZSBpbiB5b3VyIGZpbmFsIGRvY3VtZW50LiBJZiB5b3UgZ28gYmFjayB0byB0aGUgZGVmYXVsdCBgc2V0dXBgIGNodW5rIGF0IHRoZSB0b3Agb2YgeW91ciBgLlJtZGAgeW91IHNob3VsZCBzZWUgdGhpczoKCmBgYAprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKSSBkaXNjdXNzZWQgdGhpcyBjaHVuayBwcmV2aW91c2x5IGluICM1IG9mIHRoZSBbQ2h1bmsgc3RydWN0dXJlICYgb3B0aW9uc10oaHR0cHM6Ly9zdHJpLWNvbi5naXRodWIuaW8vZGF0YS1jdXJhdGlvbi8yMDIwLzA0LzA5L2xlc3Nvbi0yLyNjaHVuay1zdHJ1Y3R1cmUtb3B0aW9ucy0xKSBzZWN0aW9uIGluIExlc3NvbiAyLiBCcmllZmx5LCB0aGlzIGlzIGEgKmdsb2JhbCBjb21tYW5kKiB0aGF0IGVuc3VyZXMgYWxsIFIgY29kZSBjaHVua3MgYXJlIHZpc2libGUgaW4gdGhlIGZpbmFsIGRvY3VtZW50LCB1bmxlc3MgeW91IGVzY2FwZSB0aGlzIGJlaGF2aW9yIGJ5IHVzaW5nIGBlY2hvID0gRkFMU0VgIGluIGEgcGFydGljdWxhciBjaHVuay4gT2YgY291cnNlLCB5b3UgY291bGQgYWxzbyBzZXQgdGhlIGdsb2JhbCBvcHRpb24gdG8gYEZBTFNFYCBhcyBpcyBga25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBGQUxTRSlgIGFuZCB0aGVuIG5vbmUgb2YgdGhlIFIgY29kZSB3b3VsZCBiZSB2aXNpYmxlIGF0IGFsbC4gVGhpcyBpcyBhIHBlcmZlY3RseSBmaW5lIG9wdGlvbiBpbiBzb21lIHNpdHVhdGlvbnMgYnV0IG5vdCBpbiBvdGhlcnMuIAoKTGV0J3MgZmFjZSBpdC0tLWNvZGUgdGFrZXMgdXAgYSBsb3Qgb2Ygc3BhY2UgaW4gYSBkb2N1bWVudCBhbmQgbGFyZ2UgY29kZSBjaHVua3MgYXJlIG5vdCBwYXJ0aWN1bGFybHkgcGxlYXNpbmcgdG8gbG9vayBhdC4gWW91IG1heSBlbmNvdW50ZXIgc2l0dWF0aW9ucyB3aGVyZSB5b3UgYm90aCB3YW50IHRoZSBjb2RlIGF2YWlsYWJsZSBvbiBhIHBhZ2UgKmJ1dCogeW91IGFsc28gd2FudCB0byBoaWRlIHRoZSBjb2RlLiBGb3IgdGhpcyB3ZSB1c2UgYSB0ZWNobmlxdWUgY2FsbGVkICoqKmNvZGUgZm9sZGluZyoqKi4gTmVhciB0aGUgYm90dG9tIG9mIFtMZXNzb24gMF0oaHR0cHM6Ly9zdHJpLWNvbi5naXRodWIuaW8vZGF0YS1jdXJhdGlvbi8yMDIwLzAzLzI4L2xlc3Nvbi0wLyksIEkgdXNlZCBzb21lIHNpbXBsZSBIVE1MIHRvIG1ha2UgYSBzZWN0aW9uIHRoYXQgZm9sZHMgdGhlIFIgY29kZSBmb3IgdGhlIENsaWZmb3JkIEF0dHJhY3Rvci4gVGhlcmUgaXMgYSBsaXR0bGUgYFNob3cvaGlkZWAgYnV0dG9uIHRoYXQgYWxsb3dzIHlvdSB0byBsb29rIGF0IHRoZSBjb2RlIGlmIHlvdSB3YW50IHRvOyBvdGhlcndpc2UgaXQgaXMgaGlkZGVuIGJ5IGRlZmF1bHQuIEJ1dCB0aGlzIGFwcHJvYWNoIGlzIGEgbGl0dGxlIGNsdW5reSBiZWNhdXNlIHlvdSBtdXN0ICoqYSoqKSBrbm93IHNvbWUgSFRNTCBhbmQgKipiKiopIGluY2x1ZGUgdGhpcyBmb3IgZXZlcnkgY2h1bmsuIAoKUiBNYXJrZG93biBoYXMgYSBzaW1pbGFyIGZ1bmN0aW9uYWxpdHkgZm9yIHNob3dpbmcgYW5kIGhpZGluZyBjb2RlIGJ1dCBpdCBvbmx5IHRha2VzIGEgc2luZ2xlIGxpbmUgb2YgY29kZSBhZGRlZCB0byB0aGUgWUFNTCBoZWFkZXIuIEFnYWluLCByZXR1cm4gdG8geW91ciBZQU1MIGhlYWRlciBhbmQgYWRkIHRoZSBhcmd1bWVudCAgYGNvZGVfZm9sZGluZzpgIGFzIGEgbmVzdGVkIHByb3BlcnR5IG9mIGBodG1sX2RvY3VtZW50OmAuIFlvdXIgdHdvIG9wdGlvbnMgZm9yIGBjb2RlX2ZvbGRpbmc6YCBhcmUgYHNob3dgIGFuZCBgaGlkZWAuIAoKYGBgCm91dHB1dDoKICBodG1sX2RvY3VtZW50OgogICAgdGhlbWU6IGpvdXJuYWwKICAgIHRvYzogdHJ1ZQogICAgdG9jX2Zsb2F0OiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIGhpZ2hsaWdodDogdGFuZ28KICAgIGNvZGVfZG93bmxvYWQ6IHRydWUKICAgIGNvZGVfZm9sZGluZzogaGlkZQpgYGAKCk9uY2UgeW91IGFkZCB0aGlzIHRvIHRoZSBZQU1MIGhlYWRlciwgdGhlIGRyb3AgZG93biBgQ29kZWAgYnV0dG9uIGluIHRoZSB1cHBlciByaWdodCBjb3JuZXIgb2YgdGhlIHBhZ2Ugc2hvdWxkIG5vdyBpbmNsdWRlIGBTaG93IEFsbCBDb2RlYCBhbmQgYEhpZGUgQWxsIENvZGVgLiBUaGlzIGFsbG93cyB0aGUgdXNlciB0byBzcGVjaWZ5IGhvdyB0aGV5IHdhbnQgdG8gdmlldyB0aGUgY29kZSBpbiB0aGUgZG9jdW1lbnQuIEVpdGhlciBwcm9wZXJ0eSB5b3Ugc2V0IGZvciBgY29kZV9mb2xkaW5nYCB3aWxsIGJlIHRoZSBkZWZhdWx0IHN0YXRlIGZvciB0aGUgZW50aXJlIGRvY3VtZW50LiAKCllvdSBzaG91bGQgYWxzbyBub3RpY2UgdGhhdCBhIG5ldyBgQ29kZWAgYnV0dG9uIGFwcGVhcnMgbmV4dCB0byBldmVyeSBjb2RlIGNodW5rIGluIHlvdXIgZG9jdW1lbnQuIEFnYWluLCBpZiB5b3Ugd2FudCB0byBleGNsdWRlIHRoZSBjb2RlIGZyb20gaW5kaXZpZHVhbCBjaHVua3MsIGp1c3Qgc2V0IGBlY2hvID0gRkFMU0VgIGZvciB0aGF0IGNodW5rIGFuZCB0aGUgY29kZSB3aWxsIG5vdCBiZSBpbmNsdWRlZCBhdCBhbGwuIAoKPiBBZGQgYGNvZGVfZm9sZGluZzpgIGFyZ3VtZW50IHRvIHlvdXIgWUFNTCBoZWFkZXIgYW5kIHNldCBhIHByb3BlcnR5IHZhbHVlLiAKCjxici8+CgpBcyBmYXIgYXMgSSBrbm93IHRoZXJlIGlzIG5vIHdheSBvZiBmb2xkaW5nIHRoZSAqcmVzdWx0cyogb2YgYSBjb2RlIGNodW5rIG9yIGZvbGRpbmcgaW5kaXZ1ZHVhbCBjaHVua3MgdW5sZXNzIHlvdSB1c2UgSFRNTC4gCgpUaGF0J3MgYWxsIGZvciB0aGlzIGFzc2lnbm1lbnQuIAoKIyMgU2Vzc2lvbiBJbmZvCgpgYGB7ciBzZXNzaW9ufQpzZXNzaW9uSW5mbygpCmBgYAo=